va_arg 64位问题

我有这样的C代码。 在64位Linux系统上,结果是:4294967264而不是-32。 clang和gcc都生成具有相同错误结果的二进制文件。 行中的问题:

  * v = va_arg(args,long); 
#include  #include  #include  void setter(long *v, ...) { va_list args; va_start(args, v); *v = va_arg(args, long); va_end(args); } int main() { long v = 0; setter((long *) &v, -32); printf("%ld\n", v); return 0; } 

你实际上需要传递一个long的function。 你正在传递一个int

 setter(&v, -32L); 

在x86_64架构上, long的大小为64位。 当您将-32传递给setter() ,其类型为int且仅为32位。 如果你想要传递long ,请明确地转换它。 例如:

 setter((long *) &v, (long)-32); 

一点澄清:
如上所述,在64位体系结构中, long为64位。 然而,这不是整个故事,因为C / C ++会进行一些自动转换。 这里, setter()函数接受一个指定的参数和零个或多个未指定的参数。 -32参数是那些未指定的参数之一,因此编译器不知道实际上是long并且保留int (32位)。 此外,将额外的零推入堆栈以保持64位对齐。 这将产生如上所述的打印结果。 因此,您必须在此处明确指定您需要一个long-32L(long) -32 )。 但是如果函数实际上已经声明为void setter (long *v, long arg) ,那么编译器就会知道第二个参数是long ,并自动转换int参数。