我对以下代码和 GCC 编译器(Linux 上的 v11.4 到 x86_64)感到疯狂:
static void disasm_TESTSX_X(char *__buffer, test_inst_t *inst) {
__buffer += sprintf(__buffer, "testsx %lx", ((uint32_t)(((int32_t)(TEST_TESTSX_X_x_i)))));
}
static void disasm_TESTW_X(char *__buffer, test_inst_t *inst) {
__buffer += sprintf(__buffer, "testw %lx", (((uint32_t)(TEST_TESTW_X_x_i)) + 1L));
}
第一种形式在编译时给我一个警告(我应该使用%x),而第二种形式则没有。 TEST_TESTW_X_x_i 的类型为 uint8_t。然而,这两个表达式都显式转换为 uint32_t(代码的可读性不是很好,因为它是生成的代码)。
感谢任何可以帮助我的人。
…我应该使用%x…"testsx %lx"
两者都不正确。要将
uint32_t
转换为十六进制,请将 "testsx %lx"
更改为 "testsx %" PRIx32
并插入 #include <inttypes.h>
。
uint32_t
在某些 C 实现中可能是 unsigned
,在其他实现中可能是 unsigned long
,在其他实现中可能是其他类型。因此 %x
和 %lx
在每个 C 实现中都不会正确。 PRIx32
(在 <inttypes.h>
中定义)将被替换为字符串文字,并在所使用的 C 实现中为 uint32_t
提供正确的转换说明符。
然而,这两个表达式都显式转换为 uint32_t…
不,他们不是。第二种情况的参数是
(((uint32_t)(TEST_TESTW_X_x_i)) + 1L)
,它是 uint32_t
表达式和 1L
的和。在 C 实现中,long
比 uint32_t
宽,+
的左操作数将转换为 long
,结果的类型将为 long
。
第一种形式在编译时给我一个警告(我应该使用%x),而第二种形式则没有。 TEST_TESTW_X_x_i 的类型为 uint8_t。然而,这两个表达式都显式转换为 uint32_t(代码的可读性不是很好,因为它是生成的代码)。
是的,宏的两种扩展都会转换为类型
uint32_t
,但只有在第一种情况下,结果才会传递给 printf
。在第二种情况下,是 uint32_t
结果 加上 1L
。当求和时,操作数被转换为通用类型,并且结果具有该类型。那么,不同的转换说明符适用于不同的情况就不足为奇了。
特别是,如果您的
uint32_t
与 unsigned int
类型相同(相对常见),正确匹配的 printf
转换说明符将不会有任何宽度说明符。也就是说,您可以使用 %x
而不是 %lx
。从技术上讲,即使 long unsigned int
也是 32 位宽,这也适用。
然而,在这种情况下,整型常量
1L
的类型(即long int
)比uint32_t
具有更高的整数转换等级。因此,当执行加法时,为结果选择的类型将不是uint32_t
。如果该类型可以表示 long int
可以表示的所有值,则为 uint32_t
,否则为 unsigned long int
。 (这是“普通算术转换”的应用。)转换说明符 %lx
与类型 unsigned long int
一致。它与 [signed
] long int
不一致,但可以想象编译器不会警告这种不匹配。
总结:
您的
uint32_t
可能与 unsigned int
相同。在这种情况下,%x
是 printf
的正确 (uint32_t)(((int32_t)(TEST_TESTSX_X_x_i)))
转换说明符,但 %lx
不是。
鉴于
uint32_t
与 unsigned int
相同,((uint32_t)(TEST_TESTW_X_x_i)) + 1L)
的类型要么是 unsigned long int
(如果这也是 32 位类型),要么是 long int
。 %lx
是 printf
的正确 unsigned long int
转换说明符,但 %x
不是。 对于 long int
来说都不正确,但在这种情况下您可能不会收到有关 %lx
的警告。