我的一个项目从 GCC 工具链切换到 clang 工具链编译时,发现原本的日志输出代码有些无法编译通过,是字符串格式化说明符与数据类型不匹配导致的。举个例子:
#include <stdio.h>
#include <stdint.h>
int main() {
uint32_t a = 0;
printf("1. %u\n", a);
printf("2. %ld\n", a);
return 0;
}
// 使用 GCC 编译时,会在 printf 1 处报错 (报错信息是另外的 ESP IDF 项目编译信息复制过来的,部分内容可能会不一样):
// error: format '%u' expects argument of type 'unsigned int', but argument 6 has type 'uint32_t' {aka 'long unsigned int'} [-Werror=format=]
// 使用 clang 编译时,会在 printf 2 处报错:
// error: format specifies type 'long' but the argument has type 'uint32_t' (aka 'unsigned int') [-Werror,-Wformat]
在我这个项目中,uint32_t 在 GCC 下被解释为 long unsigned int,而在 clang 下被解释为 unsigned int。这种情况下,如果使用 "%ld" 来格式化输出 uint32_t 类型的变量,就会被 clang 编译器警告。
当然,不可能更换编译器就要将所有输出都修改一遍,所以我们可以使用 inttypes.h 头文件中定义的格式说明符来格式化输出。下面是一些常用的数据类型及其格式说明符 (包含了 size_t):
| 数据类型 | 格式说明符 | 数据类型说明 |
|---|---|---|
int8_t |
PRId8 |
有符号 8 位整数 |
uint8_t |
PRIu8 |
无符号 8 位整数 |
int_least8_t |
PRIdLEAST8 |
至少 8 位的有符号整数 |
uint_least8_t |
PRIuLEAST8 |
至少 8 位的无符号整数 |
int_fast8_t |
PRIdFAST8 |
至少 8 为的最快有符号整数类型 |
uint_fast8_t |
PRIuFAST8 |
至少 8 为的最快无符号整数类型 |
int16_t |
PRId16 |
有符号 16 位整数 |
uint16_t |
PRIu16 |
无符号 16 位整数 |
int_least16_t |
PRIdLEAST16 |
至少 16 位的有符号整数 |
uint_least16_t |
PRIuLEAST16 |
至少 16 位的无符号整数 |
int_fast16_t |
PRIdFAST16 |
至少 16 位的最快有符号整数类型 |
uint_fast16_t |
PRIuFAST16 |
至少 16 位的最快无符号整数类型 |
int32_t |
PRId32 |
有符号 32 位整数 |
uint32_t |
PRIu32 |
无符号 32 位整数 |
int_least32_t |
PRIdLEAST32 |
至少 32 位的有符号整数 |
uint_least32_t |
PRIuLEAST32 |
至少 32 位的无符号整数 |
int_fast32_t |
PRIdFAST32 |
至少 32 位的最快有符号整数类型 |
uint_fast32_t |
PRIuFAST32 |
至少 32 位的最快无符号整数类型 |
int64_t |
PRId64 |
有符号 64 位整数 |
uint64_t |
PRIu64 |
无符号 64 位整数 |
int_least64_t |
PRIdLEAST64 |
至少 64 位的有符号整数 |
uint_least64_t |
PRIuLEAST64 |
至少 64 位的无符号整数 |
int_fast64_t |
PRIdFAST64 |
至少 64 位的最快有符号整数类型 |
uint_fast64_t |
PRIuFAST64 |
至少 64 位的最快无符号整数类型 |
intmax_t |
PRIdMAX |
有符号最大整数 |
uintmax_t |
PRIuMAX |
无符号最大整数 |
intptr_t |
PRIdPTR |
有符号的整数类型,其宽度足以容纳任何指针类型,用于将指针转换为整数,并在需要整数运算的情况下进行操作 |
uintptr_t |
PRIuPTR |
无符号的整数类型,其宽度足以容纳任何指针类型,用于将指针转换为整数,并在需要整数运算的情况下进行操作 |
ptrdiff_t |
PRIdPTR |
是有符号整数类型,用于存储两个指针之间的差值 |
size_t |
"zu" |
无符号整数类型,用于存储对象的大小,其宽度足以容纳对象的大小 |
将上面的代码改成这样:
#include <stdio.h>
#include <inttypes.h>
#include <stdint.h>
int main() {
uint32_t a = 0;
printf("1. %" PRIu32 "\n", a);
return 0;
}
这样就可以在不同编译器下都能正确输出 uint32_t 类型的变量了。
如果还要了解更多,可以点进你项目中的 inttypes.h 头文件中查看更多的格式说明符。