将va_list转换为指针,然后递增它

时间:2013-09-18 13:45:17

标签: pointers casting variadic-functions

我正在使用的编译器(ARM的代码源)中存在一个错误,它打破了va_arg(),我正在尝试解决这个问题。在这种情况下,'ap'是指向32位和64位参数列表的简单指针。编译器错误是va_arg()被破坏,有时会返回不正确的值。

我可以将va_list转换为任意类型的指针,并使用它来挑选列表中的值:

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

    ival = *(int32_t*)≈
    dval = *(double*)&ap);
}

但是,如何将'ap'作为演员类型提前或后递?

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

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

真正的'C'大师可以帮我一把吗?我有一个解决方案,使用工会来操作指针,但我想要一个更“有价值”的方法......

3 个答案:

答案 0 :(得分:2)

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

使用库存加载脚本,堆栈指针(有时并非总是)加载了一个非8字节对齐的值。

我的ARM9 Linux平台没有此问题,但参数编组和va_arg()代码与ARM7编译器相同。

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

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

感谢您的回复。

答案 1 :(得分:0)

无法保证va_list可以转换为指针(可能通过涉及多个寄存器或单词的编译器魔法实现)。

您应该只使用stdarg(3)中记录的宏,即va_startva_endva_arg(可能还有va_copy)。

根据定义,您的代码不可移植且有问题,它会触发undefined behavior

增加ap仅使用va_arg(ap, int32_t)等...;

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

答案 2 :(得分:0)

无论是演员还是&运算符返回可分配值(也称为“L值”,可以在等号的左侧)。你可以尝试:

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

但是,正如之前的回答所说,va_list实现在不同平台之间会有所不同,任何解决方法都不可能是可移植的。如果您决定继续使用变通方法,至少要确保包含va_list的单元测试,以便了解它是否会中断。

相关问题