C sprintf 使用字节参数中断(Keil 编译器)

C sprintf breaks with byte parameters (Keil compiler)

我在 2 projects/platforms 中有代码 运行。它适用于一个,而不是另一个。代码是这样的:

uint8_t val = 1;
uint8_t buff[16];
sprintf(buff, "%u", val);

预期输出为“1”(gcc),但在一个编译器 (Keil) 上为 returns“511”,十六进制为 0x1FF。看起来它没有使用此编译器将 byte 提升为 int。这已得到确认,因为如果我这样做它就可以正常工作:

sprintf(buff, "%u", (int)val);

我的问题是:为什么一个编译器做我认为的 'right thing',而另一个不做?是我不正确的 expectations/assumptions、编译器设置还是其他原因?

您的假设可能是正确的,也可能是错误的。这取决于编译器的实现。所有现代(或者应该说是智能)编译器都会像你提到的那样做。但是Keil,从ver。 9.02,你需要为printf指定正确的变量长度。

这是Keil C处理各种printf函数的方式。 您需要准确指定它的长度。所有正则都是 16 位(无符号)整数,包括 %d、%x 和 %u。对 8 位使用修饰符 'b',对 32 位使用修饰符 'l'。如果你给出错误的长度,你会得到错误的数字。更糟糕的是,其余的变量都是错误的。 例如,要使用 8 位 'char',您可以使用 '%bd'(%bu 和 %bx),对于 32 位 'long' 使用 %ld、%lu 和 %lx。

char c = 0xab;
printf("My char number is correctly displayed as '0x%02bx'\n", c);

还要注意,同样,从sscanf获取数值数据,也是一样的。下面的例子是使用sscanf获取一个32位的long变量:

long var;
char *mynum = "12345678";
sscanf(mynum, "%ld", &var);

变量 var 在 sscanf 之后包含数字 12345678。 下面显示了 Keil 的 printf 系列中使用的变量的长度。

%bd, %bx, %bu - should be used for 8-bit variables

%d, %x, %u - should be used for 16-bit variables, and

%ld, %lx, %lu - should be used for 32-bit variables

为了获得最大的可移植性,您可以使用 inttypes.h 中的这些宏:(还有其他的)

PRId8, PRIx8, PRIu8 PRId16, PRIx16, PRIu16 PRId32, PRIx32, PRIu32

正常(如我所料):

#define PRIu8 "u"

但对于本例中的 Keil 编译器:

#define PRIu8 "bu"

例如,

printf("0x%"PRIx8" %"PRIu16"\n", byteValue, wordValue);

虽然这很麻烦。我建议更友好的编译器。

令人惊奇的是,即使做了几十年,您仍然对这些东西一无所知。