为什么vsprintf()位移8位数?

时间:2018-02-08 15:47:49

标签: c printf 8-bit

我在8位EFM8 MCU上使用Keil Cx51编译器。

如果我有一个功能,foo(),就像这样:

xdata char buf[32];

void foo(char *msg, ...) 
{
    va_list args;
    va_start (args, msg);
    vsprintf(buf, msg, args);
    va_end(args);
}

我这样使用它:

foo("My number is %d", 1);

buf将包含:"我的号码 256 "。

如果我将通话更改为:

foo("My number is %d", (uint16_t)1);

然后buf将包含"我的号码 1 ",正如所料。

为什么vsprintf()在没有强制转换的情况下将数字1(0x0001)向左移位8位到256(0x0100)?这是一个字节序问题吗?

1 个答案:

答案 0 :(得分:2)

已知问题是,具有“...”参数列表的函数中的参数的数据类型很重要,因为编译器通常无法自动调整数据类型。

也许某些编译器会自动检测printf中的格式说明符,并相应地调整参数中的数据类型。例如,GNU C将解析字符串并打印一条数据类型不匹配的警告消息,但调整数据类型。

如果您不使用正确的数据类型,肯定会得到不好的结果。

显然%d表示编译器为16位,1是其他数据类型(例如8位)。

可能在您的编译器中有以下形式的参数列表:

(uint8)a, (uint16)b, (uint8)c, (uint8)d

可以像这样存储在内存中:

a, high_byte_of(b), low_byte_of(b), c, d

如果函数期望c为16位值,则函数会将内存中的c解释为c的高8位,它将解释{{1}在参数列表中,d ...

的低8位

因此,如果您执行以下操作,请执行以下操作:

d

内存看起来像这样:

foo("%d, %d", 1, 2, 3, 4);

...而1, 2, 3, 4, ... 将此解释为0x102和0x304,而不是1和2。

当然在RAM中,vsprintf后跟一些与程序的这一部分无关的其他字节,因此RAM内容可能如下所示:

4

在你的情况下,RAM中的第一个字节是1, 2, 3, 4, 19, 32, 54, 21, 32, ... ,后跟一些“随机”数据(与函数调用无关的数据)。

显然1之后的第一个字节是1,因此0函数将其解释为0x0100。

如果使用vsprintf作为参数,则(uint16)1后跟0的字节将写入RAM,因此1将其解释为0x0001。