0

In Do I cast the result of malloc? it is said, that you do not need to cast the returned void pointer of the malloc() function or one of its family members, because since the standard it can be omitted and it may cause a hand of issues.

But what about the casting of a void pointer in general? Is there any difference to the general approach of casting a void pointer?

  • Should cast a void pointer to another type pointer in general in C?
  • Are there any places in C where I do cast a void pointer?
  • I would vote to close as a duplicate - nothing is different. – iBug Jan 12 '20 at 19:07
  • 1
    Yes there is: in the callback function you provide for `qsort` which has `void*` parameters. You *need* to cast them to do anything useful with them. – Weather Vane Jan 12 '20 at 19:14
  • No, @WeatherVane, you need to *convert* them to do anything useful with them. Such a conversion can be performed without a cast. By assignment to a variable of the correct type, for example. – John Bollinger Jan 12 '20 at 19:16
  • @WeatherVane or assign to variables. – Antti Haapala -- Слава Україні Jan 12 '20 at 19:16
  • @JohnBollinger I was thinking of the case where you use them directly. For example `if(*(int*)a < *(int*)b)` – Weather Vane Jan 12 '20 at 19:17
  • Sure, but you don't *need* to write your comparison function that way. It is the conversion that is essential, not the syntactic mechanism by which the conversion is specified. – John Bollinger Jan 12 '20 at 19:19
  • @JohnBollinger true, you don't need to write the function that way, but if you are working with the pointers directly, they need to be cast. OP asked for an example, not a workaround. – Weather Vane Jan 12 '20 at 19:20
  • 1
    To address the _Should I cast_, there's the usual guideline for casts: Never specify one explicitly if you don't need to. (Where "need to" is sufficiently vague to create coding style discussions.) – 1201ProgramAlarm Jan 12 '20 at 19:21
  • Agreed, @1201ProgramAlarm, so, inasmuch as this is a "should I" question, not a "must I" question, it is largely a matter of opinion. So voted. – John Bollinger Jan 12 '20 at 19:25

2 Answers2

6

There are two correct cases where you need to have a cast:

  • to convert a pointer to a void back to its original non-void type without assigning the result to a variable (assignment including initialization, or passing it as an argument).

  • to silence a stupid compiler that gives a warning about a narrowing conversion. C11/C18 Annex I:

    1. An implementation may generate warnings in many situations, none of which are specified as part of this International Standard. The following are a few of the more common situations.

    2. [...]

      • An implicit narrowing conversion is encountered, such as the assignment of a long int or a double to an int, or a pointer to void to a pointer to any type other than a character type (6.3).

For the first part: you can pretty much always use a temporary variable. For example you can either write

int comparator(const void *a, const void *b)  
{ 
    int sa = ((const struct foo *)a)->bar; 
    int sb = ((const struct foo *)b)->bar;  
    return (sa > sb) - (sa < sb); 
} 

or

int comparator(const void *a, const void *b)  
{ 
    const struct foo *sa = a; 
    const struct foo *sb = b;  
    return (sa->bar > sb->bar) - (sa->bar < sb->bar); 
} 

- they're pretty much equivalent in number of keypresses.

And for the second case you just need to avoid such compilers or try to switch off that nagging with some switches.


Beyond that the question rather is, "should I have a cast where it is not needed". There are many things that are not necessary in a C program but are added for clarity. For example indentations or newlines! Adding them makes things so much clearer. The question is whether adding a useless cast for return value from malloc for example makes it more readable:

char *foo = malloc(42);

vs

char *foo = (char *)malloc(42);

Isn't it rather obvious that the result should be converted to char * or at least that of foo even without a cast?

  • Excellent answer. Only other caution I can think of would be to make clear that you should never cast to void in attempt to overcome a compiler warning about incompatible types or in an attempt to subvert a type-punned pointer warning. – David C. Rankin Jan 12 '20 at 19:32
  • ... and that second version is much more readable imho. Typical usage has the implicit conversion variables assigned first thing in the function, effectively declaring "these `void*` are actually expected to be pointing to type `const struct foo`", along with the other contractual statements like `assert()`. – cmaster - reinstate monica Jan 12 '20 at 19:34
  • it to write `const` objects – 0___________ Jan 12 '20 at 19:37
  • People cast return of the `malloc` (as often you see it here) because VS is a very popular IDE and MS compiler compiles by default as C++. As beginners they do not clearly understand what is going on - so add something just to compile the code. – 0___________ Jan 12 '20 at 19:39
2

When you have a void*, you can implicitly convert it to any pointer type. This only works with a void*. It doesn't work for a double*, and it doesn't work for an int, which would not even be a pointer.

When you add the cast, you expand the set of allowed input types. Suddenly, any pointer is eligible for conversion as is any integral type.

Now, what happens if you cast an int to myStruct*? Exactly. Bullshit. You want the compiler to throw an error on this.


Likewise, if you have a pointer, and you convert it implicitly to a void*, that only works for pointers (and a 0 literal). If you add a cast, you lose the check that the value actually is a pointer. Now the conversion works just as well with a char as input.

And what happens when you cast a 'a' to a pointer? Exactly. Bullshit. You want the compiler to throw an error on this.


So, please, don't add unnecessary casts. They invariably broaden the potential for bugs not being caught by the compiler. If you must pass a pointer through a void*, make sure that that only works with pointers.

cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106