printf 和整数的奇怪警告

问题描述 投票:0回答:2

我对以下代码和 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(代码的可读性不是很好,因为它是生成的代码)。

感谢任何可以帮助我的人。

c format printf escaping uint32-t
2个回答
0
投票

"testsx %lx"
…我应该使用%x…

两者都不正确。要将

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


0
投票

第一种形式在编译时给我一个警告(我应该使用%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
    的警告。

© www.soinside.com 2019 - 2024. All rights reserved.