打印 uint8_t (char) with "%d" without casting takes MSB and not the LSB?

printing uint8_t (char) with "%d" without casting takes the MSB and not the LSB?

让我们看下面的代码:

#include <stdio.h>
#include <inttypes.h>

typedef enum
{
  BLAH = 9,
}fiz_e;

int main(void)
{
    fiz_e foo = BLAH;
    uint32_t bar = 9;

    printf("foo d %d x 0x%08x\n",(int)foo,(unsigned int)foo);

    if (bar == foo) printf("Hi\n");

    if (bar == (uint32_t)foo) printf("Ho\n");
    
    return 0;
}

直觉上我会说这个程序显示:

foo d 9 x 0x00000009
Hi
Ho

顺便说一句,这也是我在尝试过的每个在线编译器上编译它时得到的结果。

但是,我使用 riscv 工具链(riscv32-unknown-elf-gcc,gcc 版本 5.2.0)在 pulpino 上(交叉)编译,得到以下结果:

foo d 0 x 0x00000009
Ho

好像当不转换为 uint32_t 时,它会占用 msb 而不是截断它...

字节顺序可以解释这个吗?

标准对此有何规定?

Intuitively I would have said that this program displays:

foo d 9 x 0x00000009
Hi
Ho

分析,我也这么说。

I got the following result:

foo d 0 x 0x00000009
Ho

as if when not casting to uint32_t, it would take the msb and not truncate it...

C 不是那样工作的。

Does endianness could explain this?

没有。算术、比较和类型转换运算符的行为是根据其操作数的值而不是表示来定义的,并且指定的是结果的值,而不是其表示。

What does the standard say about this?

总结该标准的一些尚未涵盖的相关含义:

  • 枚举类型,例如您的 fiz_e,是整数类型。
  • 当被转换的值可以用目标数据类型表示时,所有转换,包括由类型转换运算符产生的转换,都是value-preserving。
  • 所有intunsigned intuint32_t(前提是实现定义了它),而你的fiz_e可以表示值9
  • intunsigned int 不受整数提升的影响,因此不会对您的 printf 调用的参数执行额外的转换。
  • 总体而言,您为 cross-compiled 二进制文件描述的行为不符合语言规范。

提供的信息不足以说明您的工具链或执行环境有什么问题,或者您使用这些工具链或执行环境的详细信息会产生您描述的 non-conforming 行为。