【问题标题】:What does casting to void* does when passing arguments to variadic functions?将参数传递给可变参数函数时,强制转换为 void* 有什么作用?
【发布时间】:2014-01-26 16:54:03
【问题描述】:

还有另一个问题是这样讨论的: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 是一个非空指针。

很明显,如果您不进行强制转换,它会将其他东西推入堆栈。它可能推动什么?为什么?

使传递非空指针未定义行为的基本原理是什么?这对我来说没有意义......

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

【问题讨论】:

  • pIReport4的类型是什么?
  • 那么pIReport4 是指向非void 的指针吗?问题是,并非所有指针都可能具有相同的表示(宽度、位模式的解释等)和对齐要求。如果确实如此,则转换为 void * 会进行必要的转换。
  • pIReport4的类型是什么?
  • pIReport4 是一个非空指针。
  • 什么编译器、架构和优化级别?

标签: c arguments void-pointers variadic-functions


【解决方案1】:

正如第二个链接中的answer 解释的那样

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

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

【讨论】:

  • 造成这种未定义行为的基本原理是什么?
  • @Calmarius:在 C 中,没有关于类型的运行时信息;在可变参数函数的情况下,编译时两者都没有——但我很好奇的是为什么默认参数提升不包括转换为void * 的对象指针,在这种情况下,我们摆脱了大部分强制转换。
  • @mafso 但是当我只考虑指针值时,void* 和 nonvoid* 有什么区别?静态类型在可变参数函数的调用点也是已知的。
  • void *char * 的位模式必须相同(据我了解标准)。但是,指向地址的“任何其他”指针不必与指向同一内存位置的char * 地址相同。我在面向字的机器 (ICL Perq) 上学习了 C,其中地址的 char * 值与同一地址的 int * 值不同。你必须非常小心 (a) 确保 malloc() 被声明(在那些日子里返回 char *voidvoid * 还没有出现),并且 (b) 你习惯于将结果转换为正确的类型。 […继续…]
  • […continuation…] 我相信标准占据了它的位置,这样机器就可以符合标准。一些大型计算机也有有趣的地址结构。
【解决方案2】:

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

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

【讨论】:

  • "默认情况下,可变参数函数的所有参数都作为传递的变量类型传递。" - 不,有默认的促销规则。
猜你喜欢
  • 2021-11-19
  • 2011-06-06
  • 1970-01-01
  • 1970-01-01
  • 2013-10-31
  • 2012-11-19
  • 2015-09-22
  • 2020-08-15
  • 1970-01-01
相关资源
最近更新 更多