Casting using the '==' operator

In my C program, I have a line where I use the '==' operator, and two operands are selected as char, for example:

char top_level_domain[sizeof(char) * 128]; ... if((char)top_level_domain[i] == ':' || (char)top_level_domain[i] == '/') 

Is it recommended / safe? If not, how do I need to check the contents of a specific element in an array?

EDIT: added declaration and removed casts to character literals

+6
source share
4 answers

In general, it is safer and more efficient to avoid casting whenever possible because it allows the compiler to perform type checking. For example, specify an error:

 // Let pretend you forgot or mixed up the type here... char **top_level_domain; // ... if ((char) top_level_domain[i] == (char) ':') ... 

Or maybe...

 char top_level_domain[sizeof(char) * 128]; ... // Whoops! forgot to type [i] if((char)top_level_domain[i] == ':' || (char)top_level_domain == '/') 

Oops! You forgot to dereference a pointer, you get garbage. The compiler would give you a diagnostic message, but since you used the broadcast, the diagnostic message disappeared.

Note: This will actually trigger a diagnostic message for some compilers, because char narrower than char * , but if we used size_t instead of char , then it would not narrow down, but it would still be an error.

Why use broadcasts?

There are quite a few situations where C "whole stocks" and "ordinary arithmetic conversions" can cause unwanted behavior. For instance,

 size_t align_to_16_bytes(size_t x) { // return x & ~15u; // WRONG return x & ~(size_t) 15u; // RIGHT } 

However, in the general case, this will only cause problems when using types wider than int , or when you mix types of signed and unsigned types that are at least equal to the width of the int .

Newer languages, such as Java and C #, largely avoid this problem, only allowing you to extend the implicit casts.

+17
source

Throws are “safe”, but useless and very bad. Typically, in C, everything that needs to be cast is bad style at best and often causes undefined behavior, so the presence of casts in the source file is a “code smell” - a sign that the author probably did something wrong and that the reader should be especially careful in finding errors.

Just remove the throws and your code will be fine.

+2
source

Listing is an explicit compiler statement that you want to override the default implicit type conversions (or taking into account their absence) that the language gives you. Generally speaking, these implicit type conversions by default are well thought out by the language developers and work with type C security, not against it.

A good example is void * , which according to section 6.5.16.1.1, C11 can be implicitly converted by assignment to a pointer or from a "pointer to any type of object". This means that you cannot, for example, implicitly convert it to a pointer to a function. This is exactly how you would like it to work when calling malloc() , for example, it must convert some other type of pointer, since you obviously cannot create objects of type void , but this makes no sense for dynamic allocating a memory block for a function. So, implicit type conversions by default here do exactly what you want - let you convert to a pointer to any type of object, since that is the whole goal, but complain loudly if you try to convert anything else.

Some people seem to think that dropping the return from malloc() makes it “explicit” what you are trying to do, but (1) you never see people who do things like int i = 1; double d = (double) i; int i = 1; double d = (double) i; They seem to make a special case of malloc() ; and (2) he doesn’t do this at all, because what the actor’s manifest does is that you want to override the default security types and conversions that C gives when what you really want to do in this case , comply with them.

As an alternative, sometimes implicit type conversions do not give you what you want, and casting should be necessary. An obvious example is integer division, which always gives you int . People who made C could provide another operator with floating point division with integers if they wanted to, but they didn't, the result is that if you want to do division with two integers and integer division, this is not what you want, then you have to drop one of them to a floating point type in order to override the default behavior in order to achieve what you want. If integer division is what you want in a particular case, then you obviously aren't using it.

So, as a rule, when C gives you the result that you want without casting, which in most cases fails. Only when used, when the default behavior of C does not give you what you want, and you are ready to explicitly give up the type of security that it gives you as a result.

+1
source

Throws are unsafe not only because of the compiler type checking problem that Dietrich Epp talks about, but also because reducing the range of values ​​can lead to false positives:

 int myValue = 'a' + 768; //A number that is not equal to 'a' assert(myValue != 'a'); //This is true... assert((char)myValue == 'a'); //...but so is this! 

Of course, this is because I built myValue in such a way as to get this false result. However, 1 / 256th of all integers will be compared with a specific character if the integer is selected in char, which represents a lot of possible false positives. This will not happen if you allow the compiler to select an integer representation for comparison.

0
source

Source: https://habr.com/ru/post/952433/


All Articles