干净的代码在C的printf的size_t ++(或:C99在C%z与最近的等效++)(Clean

2019-07-21 20:36发布

我有一些C ++代码,它打印size_t

size_t a;
printf("%lu", a);

我想这不会对32位和64位架构的警告进行编译。

如果这是C99,我可以使用printf("%z", a); 。 但AFAICT %z不以任何标准C ++方言存在。 所以不是,我必须这样做

printf("%lu", (unsigned long) a);

这实在是太丑了。

如果有打印无设施size_t的建成到语言,我不知道它是否可以写一个printf包装或诸如此类,使得将插入适当的铸件上size_t这么来消除伪编译器警告,同时仍保持良好的。

有任何想法吗?


为了澄清为什么我用printf:我有一个比较大的代码库,我清理。 它使用printf的包装做的事情,如“写一个警告,它记录到一个文件,并可能退出与一个错误代码”。 我也许能鼓起足够的C ++ - 富与COUT包装要做到这一点,但我宁愿没有改变的计划只是为了摆脱一些编译器警告的警告每()调用。

Answer 1:

大多数编译器对自己的符size_tptrdiff_t参数时,Visual C ++,例如使用的Iu%和%ID分别,我认为,GCC将允许您使用%祖和ZD%。

你可以创建一个宏:

#if defined(_MSC_VER) || defined(__MINGW32__) //__MINGW32__ should goes before __GNUC__
  #define JL_SIZE_T_SPECIFIER    "%Iu"
  #define JL_SSIZE_T_SPECIFIER   "%Id"
  #define JL_PTRDIFF_T_SPECIFIER "%Id"
#elif defined(__GNUC__)
  #define JL_SIZE_T_SPECIFIER    "%zu"
  #define JL_SSIZE_T_SPECIFIER   "%zd"
  #define JL_PTRDIFF_T_SPECIFIER "%zd"
#else
  // TODO figure out which to use.
  #if NUMBITS == 32
    #define JL_SIZE_T_SPECIFIER    something_unsigned
    #define JL_SSIZE_T_SPECIFIER   something_signed
    #define JL_PTRDIFF_T_SPECIFIER something_signed
  #else
    #define JL_SIZE_T_SPECIFIER    something_bigger_unsigned
    #define JL_SSIZE_T_SPECIFIER   something_bigger_signed
    #define JL_PTRDIFF_T_SPECIFIER something-bigger_signed
  #endif
#endif

用法:

size_t a;
printf(JL_SIZE_T_SPECIFIER, a);
printf("The size of a is " JL_SIZE_T_SPECIFIER " bytes", a);


Answer 2:

printf格式说明%zu将正常工作在C ++系统; 没有必要使问题更加复杂。



Answer 3:

在Windows和printf的Visual Studio的实施

 %Iu

我的作品。 看MSDN



Answer 4:

C ++ 11

C ++ 11吨的进口C99这样std::printf应该支持C99 %zu格式说明。

C ++ 98

在大多数平台上, size_tuintptr_t是等效的,在这种情况下可以使用PRIuPTR中定义的宏<cinttypes>

size_t a = 42;
printf("If the answer is %" PRIuPTR " then what is the question?\n", a);

如果你真的想成为安全,强制转换为uintmax_t和使用PRIuMAX

printf("If the answer is %" PRIuMAX " then what is the question?\n", static_cast<uintmax_t>(a));


Answer 5:

由于您使用C ++,为什么不使用输入输出流? 这应该是你不是用脑死C ++实现,没有定义编译没有警告,并做正确的感知类型的东西,只要operator <<用于size_t

当实际输出必须与完成printf()你仍然可以用输入输出流结合起来,以获得类型安全的行为:

size_t foo = bar;
ostringstream os;
os << foo;
printf("%s", os.str().c_str());

这不是超高效的,但你的情况与上述交易文件I / O,所以这是你的瓶颈,不是这个字符串格式化代码。



Answer 6:

这里有一个可能的解决方案,但它不是一个相当漂亮的..

template< class T >
struct GetPrintfID
{
  static const char* id;
};

template< class T >
const char* GetPrintfID< T >::id = "%u";


template<>
struct GetPrintfID< unsigned long long > //or whatever the 64bit unsigned is called..
{
  static const char* id;
};

const char* GetPrintfID< unsigned long long >::id = "%lu";

//should be repeated for any type size_t can ever have


printf( GetPrintfID< size_t >::id, sizeof( x ) );


Answer 7:

有效类型底层为size_t是依赖于实现的 。 C标准将其定义为通过sizeof运算符返回的类型; 除了是无符号和一种整体式的,在为size_t可相当多的东西,其大小可容纳()预计将在的sizeof返回的最大价值。

要用于一个为size_t可以根据在服务器上改变因此,该格式串。 它应该始终有“U”形,但可能是L或d或也许别的...

一个小窍门可以将其转换为机器上的最大的整数类型,确保在转换没有损失,然后利用这种已知类型相关的格式字符串。



Answer 8:

在C ++格式库提供了一个快速便携(安全)实施printf包括z改性剂size_t

#include "format.h"

size_t a = 42;

int main() {
  fmt::printf("%zu", a);
}

此外,它支持Python类格式字符串的语法和捕获类型信息,这样你就不必手动提供它:

fmt::print("{}", a);

它已经过测试与主要的编译器,并提供跨平台一致的输出。

免责声明 :我这个库的作者。



文章来源: Clean code to printf size_t in C++ (or: Nearest equivalent of C99's %z in C++)