为什么转换变量函数参数很重要?

Why would casting a vararg function parameter matter?

本文关键字:参数 转换 变量 函数 为什么      更新时间:2023-10-16

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

将最后一个参数转换为void*有效,但直接传递NULL (nullptr不可用)则不能:

foo(x,y,(void*)NULL);   //okay
foo(x,y,NULL);          //crash
在我看来,这不应该有什么区别,但话说回来,我以前就错了。你能想到演员阵容有什么不同的原因吗?或者这只是一个意外(某种设计或错误的构建或史密斯)。沿着这些行)

很抱歉,我不能提供更多的细节。

在c++中,NULL是一个整型常量,而(void *)NULL则是一个指针类型。

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

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

对于你的问题,整数在你的体系结构上可能不是指针大小的。(也就是说sizeof(int) != sizeof(void*))。因为NULL是作为一个整数被推送到堆栈上的,如果它不是指针大小的,那么当函数从堆栈中取出一个"指针"时,它会抓取谁知道是什么。

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

NULL是一个空指针常量,所以必须是"一个整型常量表达式prvalue,计算结果为0或std::nullptr_t类型的prvalue ."如果nullptr不可用,我们可以假设它是一个零值的整型常量prvalue,例如0。失败表明void *参数的变量调用语义与NULL(提升)类型的变量调用语义不同,例如,如果指针是64位而int是32位。