Pointers 将va_列表强制转换为指针,然后递增

Pointers 将va_列表强制转换为指针,然后递增,pointers,casting,variadic-functions,Pointers,Casting,Variadic Functions,我正在使用的编译器(针对ARM的Codesourcery)中有一个bug破坏了va_arg(),我正在尝试解决这个问题。在本例中,“ap”是指向32位和64位参数列表的简单指针。编译器的错误是va_arg()已损坏,有时会返回不正确的值 我可以将va_列表强制转换为任意类型的指针,并使用它拾取列表上的值: void foo(va_list ap) { int32_t ival; double dval; ival = *(int32_t*)≈

我正在使用的编译器(针对ARM的Codesourcery)中有一个bug破坏了va_arg(),我正在尝试解决这个问题。在本例中,“ap”是指向32位和64位参数列表的简单指针。编译器的错误是va_arg()已损坏,有时会返回不正确的值

我可以将va_列表强制转换为任意类型的指针,并使用它拾取列表上的值:

void foo(va_list ap)
{
    int32_t  ival;
    double   dval;

    ival = *(int32_t*)≈
    dval = *(double*)&ap);
}
但是,我如何在增量“ap”之前或之后将其作为强制类型

例如,这两个选项都给出了一个错误:

(int32_t*)&ap++;
++(int32_t*)&ap.

一个真正的“C”大师能帮我一把吗?我有一个解决方案,它使用联合来操作指针,但我想要一个更“c”的方法…

不能保证
va_list
可以转换为指针(它可能通过涉及多个寄存器或字的编译器魔术来实现)

您应该只使用中记录的宏,即
va_start
va_end
va_arg
(可能还有
va_copy

根据定义,您的代码是不可移植和有缺陷的,它会触发错误

要增加ap值,请仅使用
va_arg(ap、int32_t)


顺便说一句,您可以下载的新版本(即今天的4.8.1,2013年9月18日)并从源代码进行编译(可能作为交叉编译器)。它可能已经解决了您遇到的编译器错误。

强制转换和&operator都不会返回可分配的值(也就是可以位于等号左侧的“L值”)。你可以试试:

int ival;
void * pap = ≈
ival = *(int32_t*)pap;
pap += sizeof(int32_t);

但是,正如前面的回答所说,va_列表的实现在不同的平台之间会有所不同,任何解决方案都不可能是可移植的。如果您决定继续进行解决方案,至少要确保包含va_列表的单元测试,这样您就可以知道它是否中断。

事实证明,这根本不是编译器的问题。该问题是由堆栈指针不在8字节边界上引起的。通过修改加载脚本以对堆栈使用8字节对齐来修复此问题。我应该补充一点,这个项目正在使用NutOS;一段非常有用的代码

在stock load脚本中,堆栈指针被加载(有时,不总是)的值不是8字节对齐的

我的ARM9 Linux平台没有这个问题,尽管参数编组和va_arg()代码与ARM7编译器的代码相同

我注意到,当调用一个函数时,编译器加载堆栈指针,并使用它认为会导致8字节对齐的值。这导致r0-r3是8字节对齐的。对于8字节对齐,va_arg()算法有效

我知道这不能回答我的问题。我确实制定了一个涉及工会的解决方案,而且非常有趣的是,您认为额外的代码最终被优化了。因此,使用联合来操纵va_列表并没有增加太多开销


感谢大家的回复。

va_start()、va_copy()和va_end()都可以。问题是va_arg()已损坏,有时会给出错误的结果。将“ap”转换为某个类型以获得一个有效值;我的问题是如何编码递增或递减操作。是的,代码是不可移植的。没关系,这是一款使用AT91SAM7X处理器的嵌入式设备。不过你给了我一个主意,谢谢。我将尝试使用va_arg()来增加…是什么让您认为一个未定义的行为错误(可能会使用稍微不同的编译器或优化选项再次触发…)对于嵌入式处理器来说是可以的!!这没关系,因为这是一个专用的应用程序;编译器不会改变,我们可以验证我们使用的东西是否能正常工作。顺便说一句,不能使用va_arg()进行增量优化。您使用的编译器的确切版本是什么?如何调用它?我希望你的嵌入式产品是一个不重要的小工具(不是真正有用的东西,比如空调系统),我不会购买或使用它。我害怕看到这种(我觉得很不专业)行为“我不介意未定义的行为;它对我有用一次,所以对其他人应该没问题……”事实上,它不会是未定义的。修复是在对va_列表上的参数进行编组和从va_列表中选取值时,分析编译器生成的汇编代码的结果。va_arg()宏生成的代码错误地计算了地址。因此,如果您知道参数是如何编组的,那么您就知道应该如何检索它们。除非我们改变编译器(如果编译器的行为不同),否则就不会有问题。但在几个月后,随着产品的更新,您将稍微更改代码和编译器。。。。所以我很害怕(更不用说我对其余代码的质量没有信心了)。顺便说一句,我并不是建议其他人采用这种修复方法。这似乎是一个影响一些ARM实现的相对不寻常的问题。而且,我不是一个真正的程序员,但我在电视上玩一个。。。