6

When assigning to or from a void-pointer no cast is needed (C99 §6.3.2.2 sub 1 / §6.5.16.1 sub 1). Is this also true when passing a (for example int-)pointer to a function that expects a void-pointer?

For example:

void foo(void * p){
    // Do something
}

int main(){
    int i = 12;
    foo(&i); // int * to void *: no cast needed?
}

When I compile this with GCC (4.8.1, MinGW-32) I get neither errors nor warnings (with -Wall & -pedantic).

In contrast in this answer it is suggested that a cast is needed for this call (to eliminate -Wformat warnings):

int main(){
    int i = 12;
    printf("%p\n", &i);
}

But in my case GCC doesn't complain.

So: are casts needed when passing a non-void-pointer to a function that expects a void-pointer?

Community
  • 1
  • 1
Kninnug
  • 7,992
  • 1
  • 30
  • 42

1 Answers1

6

The difference is printf is a variadic function and variadic functions follow different conversion rules on their trailing arguments.

foo(&i); 

no cast is needed here as foo is a prototyped function. C says &i is converted to the type of p as if by assignment and in C there is an implicit between all object pointer types to void *.

The case with printf is different as variadic functions like printf have default argument promotions on their remaining arguments and no conversion occur on the argument of pointer types.

C on prototyped functions:

(C99, 6.5.2.2p7) "If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type."

C on variadic functions:

(C99, 6.5.2.2p7) "(C99, 6.5.2.2p7) "The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments."

So: are casts needed when passing a non-void-pointer to a function that expects a void-pointer?

For printf, p conversion specifier requires a void * argument. If the argument is of a different type, the function call invokes undefined behavior. So if the argument of p is an object pointer type, the (void *) cast is required.

(C99, 7.19.6.1p8) "p The argument shall be a pointer to void."

ouah
  • 142,963
  • 15
  • 272
  • 331
  • 1
    You seem to have quoted the same sentence on both "C on prototyped functions" and ".. variadic ..", I assume you mean the second part of paragraph 7? *"The ellipsis notation.."* – Kninnug Dec 06 '13 at 23:04
  • 1
    You stopped quoting before the relevant part for calls to variadic functions: "The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments". And promotions are only performed for integer types and float, not for pointers. – Michael Burr Dec 06 '13 at 23:06
  • Yes, I pasted two times the same paragraph by mistake as I had to leave. Now, I'm away, will fix it when back. Or if anyone wants to fix my answer, he's welcome:) – ouah Dec 06 '13 at 23:09
  • What does it mean by trailing arguments? – haccks Dec 06 '13 at 23:20
  • 1
    @haccks the trailing arguments are the arguments that relate to the ellipsis notation (the `...` in `printf` prototype). – ouah Dec 07 '13 at 00:42
  • Since people seem to be quoting your answer as though it's authoritarian, and don't get me wrong, you are a very knowledgeable person... but I think you should cite [6.2.5p28](http://www.iso-9899.info/n1570.html#6.2.5p28) and it's footnote, which states that `char *` (and other "pointer to character" types) are interchangeable as arguments of type `void *`; no conversion is necessary... – autistic Aug 20 '15 at 08:58
  • @Freenode-newbostonSebivor I actually didn't quote it on purpose. C says `void *` and `char *` (and other pointers to character variants) have the same representation and alignment. For this reason I know a lot of C experts that argue that omitting the cast for example in `char *p = ...*; printf("%p\n", p);` is valid. – ouah Aug 20 '15 at 10:01
  • @Freenode-newbostonSebivor My opinion is although the (non-normative) footnote of your quote says this implies interchangeability, the C Standard is also very clear with the `p` conversion specifier that the *argument shall be a pointer to void*. I think it's a grey zone in the Standard and I'd love to see a DR that clarify it. – ouah Aug 20 '15 at 10:02