twk*_*twk 32 c c++ printf cross-platform size-t
在跨平台的c/c ++项目(Win32,Linux,OSX)中,我需要使用*printf函数来打印一些size_t类型的变量.在某些环境中,size_t是8个字节,而在其他环境中它们是4.在glibc上我有%zd,在Win32上我可以使用%Id.有一种优雅的方式来处理这个问题吗?
fin*_*nnw 20
的PRIuPTR宏(从<inttypes.h>还)定义为一个十进制格式uintptr_t,这应该总是足够大,则可以施放size_t到它不截断,例如
fprintf(stream, "Your size_t var has value %" PRIuPTR ".", (uintptr_t) your_var);
Run Code Online (Sandbox Code Playgroud)
小智 13
这里真的有两个问题.第一个问题是三个平台的正确printf说明符字符串是什么.请注意,这size_t是一种无符号类型.
在Windows上,使用" %Iu".
第二个问题是如何支持多个平台,因为格式字符串之类的东西可能在每个平台上都不同.正如其他人所指出的那样,使用#ifdef会很快变得难看.
而是为每个目标平台编写单独的makefile或项目文件.然后通过源文件中的某个宏名称引用说明符,在每个makefile中相应地定义宏.特别是,GCC和Visual Studio都接受"D"开关来在命令行上定义宏.
如果您的构建系统非常复杂(多个构建选项,生成的源等),维护3个单独的makefile可能会变得难以处理,并且您将不得不使用某种高级构建系统,如CMake或GNU autotools.但基本原理是相同的 - 使用构建系统来定义特定于平台的宏,而不是将平台检测逻辑放在源文件中.
我唯一能想到的是典型的:
#ifdef __WIN32__ // or whatever
#define SSIZET_FMT "%ld"
#else
#define SSIZET_FMT "%zd"
#endif
Run Code Online (Sandbox Code Playgroud)
然后利用恒定折叠:
fprintf(stream, "Your size_t var has value " SSIZET_FMT ".", your_var);
Run Code Online (Sandbox Code Playgroud)
小智 5
Dan Saks 在《嵌入式系统设计》中撰写了一篇文章,讨论了这个问题。根据 Dan 的说法,%zu 是标准方式,但很少有编译器支持这种方式。作为替代方案,他建议使用 %lu 以及将参数显式转换为 unsigned long:
Run Code Online (Sandbox Code Playgroud)size_t n; ... printf("%lu", (unsigned long)n);
我不知道有什么令人满意的解决方案,但您可能会考虑使用专门的函数将 size_t 项格式化为字符串,并打印该字符串。
(或者,如果你能摆脱它,boost::format 可以轻松处理这种事情。)