3

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

将最后一个参数转换为void*有效但直接传入NULLnullptr不可用)不会:

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

IMO 这不应该有所作为,但话又说回来,我以前错了。你能想到演员会产生影响的任何原因吗?或者这仅仅是一个意外(一些不同步或错误的构建或smth。沿着这些线)

提前抱歉,我无法提供更多细节。

4

3 回答 3

12

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

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

于 2013-03-22T14:57:16.143 回答
2

当您使用可变数量的参数(可变参数函数)时,构建堆栈的方式遵循构建堆栈的基于类型的规则。但是被调用的函数肯定不知道堆栈上的真正内容。它只需要做出假设并继续。这就是为什么将错误的参数传递给 printf 是如此危险的原因——如果你告诉它期待一个长整数,而你只给它一个短整数,它会从堆栈中读取比你放入的数据更多的数据,而且不好事情会发生。

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

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

于 2013-03-22T15:07:29.413 回答
1

NULL是一个空指针常量,所以必须是“整数类型的整数常量表达式纯右值,其计算结果为零或类型的纯右值std::nullptr_t ”如果nullptr不可用,我们可以假设它是一个零值整数常量纯右值,例如0。失败表明 varargs 调用语义对于void *参数和那些(提升的)类型的参数不同NULL,例如,如果指针是 64 位和int32 位。

于 2013-03-22T15:00:51.943 回答