当将参数传递给可变参数函数时,转换为void *会做什么?

时间:2014-01-08 14:19:52

标签: c arguments void-pointers variadic-functions

还有另一个问题,讨论类似这样的问题:When printf is an address of a variable, why use void*?,但它只回答了为什么不应该将指针打印为整数。

另一个问题是,在将它们传递给可变函数时,应始终将指针转换为void *:Argument conversion: (normal) pointer to void pointer, cast needed?。它说如果你不这样做,你会调用未定义的行为,但它不会超出这个范围。

事实上:

      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);
      }

打印:

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是一个非void指针。

很明显,如果不进行演员表演,它会将其他东西推入堆栈。它会推动什么?为什么呢?

传递非void指针未定义的行为的理由是什么?这对我来说没有意义......

我一直认为指针转换只是编译器在读取或写入时如何解释指向数据的提示。但是当只传递指针值时,我会期望它传递相同的字节序列而不管类型。

2 个答案:

答案 0 :(得分:3)

第二个链接中的answer解释了

  

对于printfp转化说明符需要void *个参数。如果参数的类型不同,则函数调用将调用未定义的行为。因此,如果p的参数是对象指针类型,则需要(void *)强制转换。

也就是说,由于您的代码片段会调用未定义的行为,因此您可以获得任何预期或意外结果。您获得的结果也可能因编译器而异。在我的编译器(GCC 4.8.1)上,它给出了结果:
enter image description here

答案 1 :(得分:0)

默认情况下,variadic函数的所有参数都作为传递的变量的类型传递。

你没有提到pIReport4是什么类型,但假设它是例如int,那么它将在堆栈上作为4个字节传递。如果您恰好位于64位系统上,则sizeof(void *)8字节。因此printf将从堆栈中读取8个字节,并且存在未定义的行为。