Need some clarification regarding casting in C

后端 未结 13 2102
野趣味
野趣味 2020-12-20 04:01

I was just reading about the bad practice of casting the return value of malloc. If I understood correctly, it is absolutely legal to leave the cast as it is do

相关标签:
13条回答
  • 2020-12-20 04:33
    double bar = foo();
    

    What happens here is called promotional conversion, where the value of the casted variable is reserved after the conversion. The reverse is not true, i.e. float -> double. The only answer is to cast only when you really need to. Casting a lot is a sign of bad design.

    0 讨论(0)
  • 2020-12-20 04:33

    In your example there's a loss of precision, but the cast is implicit. There are times when casting is absolutely necessary, such as when you're reading data from a byte stream or when all you have is data coming in through a void* pointer, but you know what data it represents. But for most part, casting should be avoided and reserved for these extreme cases.

    0 讨论(0)
  • 2020-12-20 04:33

    Basically you need to cast arguments to functions that expect a different parameter than their prototype claims.

    For example, isalpha() has a prototype with an int argument, but really expects an unsigned char.

    char *p;
    if ((*p != EOF) && isalpha((unsigned char)*p) /* cast needed */
    {
        /* ... */
    }
    

    And, you need to be extra careful with functions that accept a variable number of arguments, eg:

    long big;
    printf("%d\n", (int)big);
    

    Edit

    The compiler cannot convert the arguments of variadic functions to the proper type, because there is no type information available in the prototype itself. Consider a printf()-like function

    int my_printf(const char *fmt, ...);
    

    As far as the compiler is aware, you can pass values of all kinds of types in the "..." argument, and you must make sure the arguments match what the function expects. For example, let's say the my_printf() function accepts a value of type time_t with a corresponding "%t" specifier in the format string.

    my_printf("UNIX Epoch: %t.\n", 0);         /* here, 0 is an int value */
    my_printf("UNIX Epoch: %t.\n", (time_t)0); /* and here it is a time_t */
    

    My compiler does not want to make this fail! Apparently it (and the one at codepad too) passes 8 bytes for each argument in "..."

    Using a prototype without "..." ( int my_printf(const char *fmt, time_t data); ), the compiler would automagically convert the first 0 to the right type.

    Note: some compilers (gcc included) will validate the arguments against the format string for printf() if the format string is a literal string

    0 讨论(0)
  • 2020-12-20 04:36

    You might find these two SO posts informative:

    Specifically, what’s dangerous about casting the result of malloc?

    Do Implict Function Declarations in C Actually Generate Object Code?

    0 讨论(0)
  • 2020-12-20 04:39

    The admonition against casting the result of malloc() is a special case, due to C implicitly typing the result of previously undeclared functions to int (which IINM is disallowed as of C99).

    Generally, you want to limit the use of explicit casts as much as possible; the only time you need to use one is if you're trying to assign a value of one type to a variable of an incompatible type (e.g., assign a pointer value to an int variable or vice versa). Since void * is compatible with every other pointer type, no explicit cast is needed. However, if you're trying to assign a value of type int * to a variable of type struct foo *, an explicit cast is required. If you find yourself assigning values of incompatible types a lot, then you may want to revisit your design.

    0 讨论(0)
  • 2020-12-20 04:46

    There are several situations that require perfectly valid casting in C. Beware of sweeping assertions like "casting is always bad design", since they are obviously and patently bogus.

    One huge group of situations that critically relies on casts is arithmetic operations. The casting is required in situations when you need to force the compiler to interpret arithmetic expression within a type different from the "default" one. As in

    unsigned i = ...;
    unsigned long s = (unsigned long) i * i;
    

    to avoid overflow. Or in

    double d = (double) i / 5;
    

    in order to make the compiler to switch to floating-point division. Or in

    s = (unsigned) d * 3 + i;
    

    in order to take the whole part of the floating point value. And so on (the examples are endless).

    Another group of valid uses is idioms, i.e. well-established coding practices. For example, the classic C idiom when a function takes a const pointer as an input and returns a non-const pointer to the same (potentially constant) data, like the standard strstr for example. Implementing this idiom usually requires a use of a cast in order to cast away the constness of the input. Someone might call it bad design, but in reality there's no better design alternative in C. Otherwise, it wouldn't be a well-established idiom :)

    Also it is worth mentioning, as an example, that a pedantically correct use of standard printf function might require casts on the arguments in general case. (Like %p format specifier expecting a void * pointer as an argument, which means that an int * argument has to be transformed into a void * in one way or another. An explicit cast is the most logical way to perform the transformation.).

    Of course, there are other numerous examples of perfectly valid situations when casts are required.

    The problems with casts usually arise when people use them thoughtlessly, even where they are not required (like casting the return of malloc, which is bad for more reasons than one). Or when people use casts to force the compiler to accept their bad code. Needless to say, it takes certain level of expertise to tell a valid cast situation from a bad cast one.

    In some cases casts are used to make the compiler to stop issuing some annoying and unnecessary warning messages. These casts belong to the gray area between the good and the bad casts. On the one hand, unnecessary casts are bad. On the other hand, the user might not have control over the compilation settings, thus making the casts the only way to deal with the warnings.

    0 讨论(0)
提交回复
热议问题