为什么抛出vararg函数参数很重要?

时间:2013-03-22 14:54:23

标签: c++ casting variadic-functions

最近我遇到了一个接受可变数量的参数的函数的问题,并期望最后一个参数是一个空指针。 我无法访问其实现。

将最后一个参数投放到void*有效,但直接传递NULLnullptr不可用)不会:

foo(x,y,(void*)NULL);   //okay
foo(x,y,NULL);          //crash

IMO这不应该有所作为,但话说回来,我以前错了。你能想出演员会有什么不同的原因吗?或者这只是一个意外(一些不连续或错误的构建或smth。沿着这些线)

提前抱歉我无法提供更多详情。

3 个答案:

答案 0 :(得分:12)

嗯,NULL是C ++中的整数常量,而(void *)NULL绝对是指针类型。

因此,当插入var-arg列表时,可以想象它们具有不同的大小。所以如果比方说它之后有另一个参数,这肯定会有所不同。如果没有,你最终可能会从var-arg函数中读取半垃圾。

答案 1 :(得分:2)

当您使用可变数量的参数(可变参数函数)时,堆栈的构建方式遵循基于类型的规则来构建堆栈。但被调用的函数肯定不知道堆栈上究竟是什么。它只需要做出假设并继续下去。这就是为什么将错误的参数传递给printf是如此危险 - 如果你已经告诉它期望一个long int,并且你只给它一个短的int,那么它将从堆栈读取的数据比你输入的更多,而且不好事情会发生。

对于您的问题,整数可能不是您的架构上的指针大小。 (也就是说,sizeof(int)!= sizeof(void *))。由于NULL作为整数被压入堆栈,如果它不是指针大小,那么当函数从堆栈中拉出“指针”时,它就会抓住谁知道什么。

整数可能最终出现在寄存器中,而指针最终会出现在堆栈中,或者可能是不同的寄存器文件。我从未在可变函数中看到过这种情况,但我怀疑至少有一些编译器&架构可以做到这一点。在这种情况下,被调用函数正在查找数据的错误位置,再次,没有任何好处来自它。

答案 2 :(得分:1)

NULL是一个空指针常量,因此必须是“整数类型的整数常量表达式prvalue,其求值为零或者std::nullptr_t的prvalue。”如果nullptr不可用我们可以假设它是零值整数常量prvalue,例如0。失败表明varargs调用语义对于void *参数和(提升的)类型NULL的参数不同,例如如果指针是64位而int是32位。