C/C++跨平台不同数据类型打印

C/C++中跨平台打印不同数据类型的技巧
Views: 237
1 0
Read Time:1 Minute, 19 Second

在我们日常开发中,经常会涉及到一些Debug日志的打印,此时可能需要打印各种数据类型的变量值,从而进行诊断。

此时我们一般有两种选择,一种是使用stdout流输出的方式进行打印;另外一种则是使用printf结合占位符的形式进行打印。这里简单举例如下:

int a = 1;
int64_t b = 2;

//占位符打印
printf("%lld,%d\n", a, b);
//流输出打印
std::cout << a <<","<< b <<std::endl;

其中stdout流失输出的方式写起来不够简洁,个人不喜欢使用;相反更喜欢使用printf结合占位符的方式来进行打印。

常规情况下,我们使用C/C++打印变量时都会使用占位符,而不同的数据类型需要搭配不同的占位符才能正常进行打印,以下是一些常用数据类型对应的占位符清单:

数据类型占位符备注
char%c用于打印字符
char*,char[]%s用于打印以\0结尾的字符串
int%d十进制有符号整数
long%ld 十进制有符号长整型
long long%lld 
unsigned int%u十进制无符号整数
unsigned int%o八进制无符号整数
unsigned int%x十六进制无符号整数,小写
unsigned int%X十六进制无符号整数,大写
unsigned long%lu 十进制无符号长整型
unsigned long long%llu 
float%f浮点数
double%lf双精度浮点数
pointer%p任何指针类型

但在某些时候,我们使用占位符打印可能会存在问题,比如此种场景:

uint64_t product_seq=45845454;
printf(“product sequence is %lu”, product_seq);

如果我们在64位平台上进行编译运行,不会有任何问题;但如果我们在32位平台上运行,则会提示报错,报错的信息提示此处应当使用的占位符为%llu而非%lu。

这是因为uint64_t 在64位平台上对应的数据类型是unsigned long,在32位平台上则是unsigned long long,如果我们再使用%lu就会报错。

如何解决一定位长的数据在不同平台上的数据类型不一致而导致占位符打印失败呢,其实C/C++语言标准规范制定者已经考虑到了这种问题,并给出了相应的解决方案。我们在C中可以引用inttypes.h,而在C++中引用cinttypes头文件,再结合具体的宏即可实现优雅的跨平台打印。如下示例:

#C example
include <inttypes.h>
uint64_t product_seq=45845454;
printf(“product sequence is %” PRIu64, product_seq);

#C++ example
include <cinttypes>
uint64_t product_seq=45845454;
printf(“product sequence is %” PRIu64, product_seq);

所以当我们需要跨平台打印不同位长的数据类型时,我们最好摒弃直接使用占位符进行打印的方式,转而利用官方标准定义中的宏来帮助我们进行打印,这里是一些对应表:

数据类型十进制十六进制备注
int8_tPRId8/ PRIi8  
int16_tPRId16/PRIi16  
int32_tPRId32/PRIi32  
int64_tPRId64/PRIi64  
uint8_tPRIu8PRIx8如需要大写则将x变为X
uint16_tPRIu16PRIx16如需要大写则将x变为X
uint32_tPRIu32PRIx32如需要大写则将x变为X
uint64_tPRIu64PRIx64如需要大写则将x变为X

这里我们可以再进一步,探究其实现的原理,这里我们可以找到inttypes.h头文件,看看关于PRIu64的定义:

#define PRIu8               "u"                   /* uint8_t */
#define PRIu16              "u"                   /* uint16_t */
#define PRIu32              "u"                   /* uint32_t */
#define PRIu64              __PRI_64_prefix"u"    /* uint64_t */

这里我们可以看到PRIu64会被替换为__PRI_64_prefix”u”,而__PRI_64_prefix的定义在该头文件中:

#ifdef __LP64__
#define __PRI_64_prefix  "l"
#define __PRI_PTR_prefix "l"
#else
#define __PRI_64_prefix "ll"
#define __PRI_PTR_prefix
#endif

这段宏定义的作用其实就是根据宏__LP64__来设置__PRI_64_prefix,在不同的平台中其会被不同的值取代。由此,__PRI_64_prefix”u”在64位平台上就是lu,在32位平台上就是llu,在预处理阶段就完成了替换,从而实现了跨平台的类型适配。

Happy
Happy
100 %
Sad
Sad
0 %
Excited
Excited
0 %
Sleepy
Sleepy
0 %
Angry
Angry
0 %
Surprise
Surprise
0 %
FranzKafka95
FranzKafka95

极客,文学爱好者。如果你也喜欢我,那你大可不必害羞。

Articles: 86

Leave a Reply

Your email address will not be published. Required fields are marked *

en_USEN