3

There is another question that discusses something like this: When printf is an address of a variable, why use void*?, but it only answers why shouldn't you print pointers as ints.

Another question discusses you should always cast pointers to void* when passing them to variadic functions: Argument conversion: (normal) pointer to void pointer, cast needed?. It says if you don't do so you invoke undefined behavior, but it doesn't go beyond that.

Indeed:

      if (pIReport4 == NULL)
      {
          printf("It's NULL but when I print it, it becomes: %p\n", pIReport4);
          printf("It's NULL but when I print it and cast it into (void*), it becomes: %p\n", (void*)pIReport4);
          printf("And NULL is: %p\n", NULL);
      }

Prints:

It's NULL but when I print it, it becomes: 0xc68fd0
It's NULL but when I print it and cast it into (void*), it becomes: (nil)
And NULL is: (nil)

pIReport4 is a non-void pointer.

It's clear it's pushing something else into the stack if you don't do the cast. What might it push? Why?

What's the rationale of making passing non-void pointers undefined behavior? It doesn't make sense to me...

I always thought pointer casting is just a hint to compiler how to interpret the pointed data when reading or writing it. But when passing just the pointer value I would expect that it passes the same sequence of bytes regardless of type.

10
  • What is the type of pIReport4? Commented Jan 8, 2014 at 14:23
  • So is pIReport4 a pointer to non-void? The thing is, not all pointers may have the same representation (width, interpretation of bit pattern, etc.) and alignment requirements. Casting to void * does the necessary conversion if this is indeed the case. Commented Jan 8, 2014 at 14:23
  • What is the type of pIReport4? Commented Jan 8, 2014 at 14:23
  • pIReport4 is a non-void pointer. Commented Jan 8, 2014 at 14:26
  • 1
    What compiler, architecture and optimization level? Commented Jan 8, 2014 at 14:29

2 Answers 2

4

As the answer in the second link explains that

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 pis an object pointer type, the (void *) cast is required.

That is, since your code snippet invokes undefined behavior, you can get anything, either expected or unexpected result. The result you are getting may also vary compiler to compiler. On my compiler (GCC 4.8.1) it is giving the result:
enter image description here

Sign up to request clarification or add additional context in comments.

9 Comments

What's the rationale of making this undefined behavior?
@Calmarius: In C, there is no runtime information about types; in case of a variadic function there is neither at compile time—but what I'm curious about is why default argument promotions don't include object pointers being converted to void *, in which case we got rid of most of the casts.
@mafso But what's the difference between void* and nonvoid* when I consider the pointer value only? Also the static types are known at the call site of the variadic function.
The bit patterns for void * and char * must be the same (as I understand the standard). However, the 'anything else' pointer to an address does not have to be the same as the char * address to the same memory location. I learned C on a word-oriented machine (ICL Perq), where the char * value for an address was different from the int * value for the same address. You got to be very careful about (a) ensuring malloc() was declared (returning char * in those days; void and void * were not yet around), and (b) you got used to casting the result to the correct type. […continued…]
[…continuation…] I believe the standard takes the position it does so that machines such as that can comply with the standard. Some mainframe computers also have interesting address structures.
|
0

By default all arguments to variadic functions are passed as the type of the variable passed.

You did not mention what type pIReport4 is, but assuming it's for example an int then it will be passed as 4 bytes on the stack. If you happen to be on a 64-bit system then sizeof(void *) is 8 bytes. Thus printf will read 8 bytes from the stack and there is your undefined behaviour.

1 Comment

"By default all arguments to variadic functions are passed as the type of the variable passed." - no, there are default promotion rules.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.