2013-03-22 96 views
3

最近我遇到了一个函数的问题,它接受可变数量的参数,并期望最后一个参数为空指针。 我无法访问其实施。为什么要投射可变参数函数参数?

铸造是最后一个参数一个void*工作,但传递NULLnullptr不适用)直接将不会:

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

IMO这不应该有所作为,但话又说回来,我以前是错的。你能想到演员会有所作为的任何理由吗?或者这只是一个意外事件(一些异步或错误的构建或沿着这些线路)

对不起,我不能提供更多的细节。

+3

因为'NULL'是一个整数,'(void *)NULL'是一个指针吗?可变参数不会像普通函数那样转换任何东西。 – Pubby 2013-03-22 14:55:49

+0

@Pubby我只是不明白这是如何重要的功能。你能提供一个例子吗? – 2013-03-22 14:56:12

+0

我认为这是问题,请使用nullptr代替它,它应该工作 – Felics 2013-03-22 14:56:33

回答

12

那么,NULL是一个在C++中的积分常数,而(void *)NULL是非常明确的指针类型。

因此,当插入到var-arg列表中时,它们可能会有不同的大小。所以这肯定会有所作为,例如,如果还有其他参数。如果没有,你最终可能会从var-arg函数中读取一半的垃圾。

+0

当然,大小不同。我错过了。很快会接受。 – 2013-03-22 14:58:14

1

NULL是一个空指针常数,所以必须是“整数类型的积分常量表达式prvalue计算结果为零或std::nullptr_t类型的prvalue。”如果nullptr不可用,我们可以假定它是一个零值整数常数prvalue例如0。失败指示可变参数调用语义对于void *参数和NULL(促进)类型的参数是不同的,例如,如果指针是64位,并且int是32位。

2

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

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

整数可能在寄存器中结束,而指针最终在堆栈上,或者可能是一个不同的寄存器文件。我从来没有在可变参数函数中看到过这种情况,但我怀疑至少有一些编译器能够做到这一点。在这种情况下,被调用的函数正在寻找数据的错误位置,再次,没有什么好处。

相关问题