如何以可移植的方式将可变参数列表传递给 vprintf?

How to pass a variable list of parameters to vprintf in a portable way?

我有一个代码可以从设备接收 32 位值的二进制数组并使用 vsprintf 打印它们,如下所示:

void print_stuff(int32_t *p, const char *format)
{
    vprintf( format, (va_list)p);
}

(这是简化的;确保值与格式等匹配)

基本上这依赖于正常的 x86 va_list 只是一个指针(或数组)。编译时没有警告。

现在我需要将其移植到 ARM (arm-linux-gnueabihf) 和 x64,它甚至无法编译。 ARM 的 GCC 4-something 说 "error: conversion to non-scalar type requested"

如何以可移植的方式从二进制数组生成 va_list?或者至少分别用于 32 位和 64 位拱门 - 没有任何 "native call interface" 库是可能的吗? 如果这是不可能的,那么是否有任何其他标准或 GNU 库函数适合此任务?

调用它的代码示例:

#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#ifndef __GNUC__
#error Only Linux, other platforms/compilers not needed
#endif

int main() {
uint32_t data[10];
int i;
const char *fmt = "%x %x %x %x\n";
// Simulation of reading the data
for(i = 0; i < 10, i++) data[i] = 0x100 + i;
print_stuff(data, fmt);
return 0;
}

将突出的评论转化为近似答案。

您必须检查和修改调用代码才能正确完成工作。或者你放弃对 vprintf() 的简单调用并更加努力地工作。

如果您将数组传递给打印函数,则不会传递 va_list。有各种各样的事情碰巧适用于某些特定的实现,但不适用于所有的实现。你发现的是你当前的系统在它的小生境中工作,但现在它需要离开它的小生境,它不再工作了。欢迎来到 'undefined behaviour' 的世界。使用未定义行为的代码不需要工作;它也不需要失败。

即使您修改了问题,也没有(可移植的)方法可以做到。时期。数组中有多少条目?格式字符串是什么样的?要打印的项目数是否固定?基本上,您可能会减少到:

int n_fields = count_fields(format);
switch (n_fields)
{
case 1: printf(format, p[0]); break;
case 2: printf(format, p[0], p[1]); break;
…
}

便携且可靠。如果数组中的项数是固定的(您的代码显示使用了 4 个条目),您当然不需要进行计数或切换。

您可以查找libffi;或许能帮到你。

由于格式是预定义的,您确切地知道要传入多少个参数。因此,将您需要的参数准确地传递给您的函数,而不是传递一个数组。然后您将函数更改为使用 ... 作为参数并从中获得 va_list

所以你的函数看起来像这样:

void print_stuff(const char *format, ...)
{
    va_list args;

    va_start(args, format);
    vprintf(format, args);
    va_end(args);
}

你会这样称呼它:

const char *fmt = "%x %x %x %x\n";
...
print_stuff(fmt, data[0], data[1], data[2], data[3]);