提问人:Luchian Grigore 提问时间:3/22/2013 更新时间:3/22/2013 访问量:239
为什么转换 vararg 函数参数很重要?
Why would casting a vararg function parameter matter?
问:
最近,我遇到了一个问题,该函数接受可变数量的参数,并期望最后一个参数为空指针。我无权访问它的实现。
将最后一个参数转换为工作参数,但直接传入(不可用)不会:void*
NULL
nullptr
foo(x,y,(void*)NULL); //okay
foo(x,y,NULL); //crash
IMO 这不应该有什么不同,但话又说回来,我以前错了。你能想出任何理由让演员们有所作为吗?或者这只是一个意外(一些不同步或错误的构建或沿着这些路线的 smth)
很抱歉,我无法提供更多详细信息。
答:
嗯,是 C++ 中的一个整数常量,而绝对是一个指针类型。NULL
(void *)NULL
因此,可以想象,当它们插入到 var-arg 列表中时,它们可能会有不同的大小。因此,如果后面有另一个参数,这肯定会有所作为。如果没有,你最终可能会从 var-arg 函数内部读取半垃圾。
NULL
是 null 指针常量,因此必须是“计算结果为零的整数类型的整数表达式 prvalue 或 std::nullptr_t
类型的 prvalue”。如果不可用,我们可以假设它是一个零值整数常量 prvalue,例如 .失败表明参数和(提升)类型的 varargs 调用语义不同,例如,如果指针是 64 位和 32 位。nullptr
0
void *
NULL
int
当您使用可变数量的参数(可变参数函数)时,堆栈的构建方式将遵循基于类型的堆栈构建规则。但是被调用的函数并不能肯定地知道堆栈上到底有什么。它只需要做出假设并继续前进。这就是为什么将错误的参数传递给 printf 如此危险的原因——如果你告诉它期待一个长 int,而你只给它一个短 int,它会从堆栈中读取比你输入的数据更多的数据,并且会发生不好的事情。
对于您的问题,整数在您的体系结构上可能不是指针大小。(也就是说,sizeof(int) != sizeof(void*))。由于 NULL 作为整数被推送到堆栈上,如果它没有指针大小,那么当函数从堆栈中拉出“指针”时,它会抓取谁知道什么。
整数可能最终出现在寄存器中,而指针最终出现在堆栈上,或者可能位于不同的寄存器文件中。我从未在可变参数函数中看到过这一点,但我怀疑至少有一些编译器和架构可以做到这一点。在这种情况下,被调用的函数在错误的位置查找数据,同样,它没有任何好处。
评论
NULL
(void*)NULL