代码之家  ›  专栏  ›  技术社区  ›  Justin L.

在C++中对Primtf siZeHT的代码进行清除(或者:C++中最接近的C99的%Z)

  •  94
  • Justin L.  · 技术社区  · 15 年前

    我有一些C++代码打印一个 size_t :

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

    我希望在32位和64位体系结构上不带警告地编译它。

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

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

    真的很难看。

    如果没有打印设备 西泽特 是内置在语言中的,我想知道是否可以编写一个printf包装器或这样的东西来插入适当的强制转换 西泽特 以便在保持良好的编译器警告的同时消除伪编译器警告。

    有什么想法吗?


    编辑 为了澄清我为什么使用printf:我有一个相对较大的代码库,我正在清理它。它使用printf包装器来执行诸如“编写警告,将其记录到文件中,并可能在出现错误时退出代码”之类的操作。我也许可以收集足够的C++FO来使用CUT包装器,但是我宁愿不改变程序中的每个WAR()调用,只是为了消除一些编译器警告。
    8 回复  |  直到 8 年前
        1
  •  60
  •   SergA dalle    10 年前

    大多数编译器都有自己的说明符 size_t ptrdiff_t 参数,VisualC++例如分别使用%IU和%ID,我认为GCC将允许您使用%ZU和%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);
    
        2
  •  65
  •   Will    15 年前

    这个 printf 格式限定符 %zu 在C++系统上工作很好,没有必要使它更复杂。

        3
  •  16
  •   Iceland_jack    13 年前

    在Windows和Visual Studio上实现printf

     %Iu
    

    为我工作。 看见 msdn

        4
  •  16
  •   Oktalist    8 年前

    C++ 11

    C++ 11导入C99 std::printf 应该支持C99 %zu 格式说明符。

    C++ 98

    在大多数平台上, size_t uintptr_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));
    
        5
  •  10
  •   Warren Young    13 年前

    既然你使用C++,为什么不使用IOFFROW呢?如果不使用没有定义的脑死亡C++实现,则不需要警告就可以编译并执行正确类型感知的事情。 operator << 对于 size_t .

    当必须完成实际输出时 printf() ,您仍然可以将其与iostreams结合使用以获得类型安全行为:

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

    它不是超高效的,但是上面的案例处理的是文件I/O,所以这是您的瓶颈,而不是这个字符串格式代码。

        6
  •  7
  •   stijn    12 年前

    这是一个可能的解决方案,但不是一个很好的解决方案。

    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 ) );
    
        7
  •  3
  •   mjv    15 年前

    基础的有效类型 大小取决于实现 . C标准将其定义为size of运算符返回的类型;除了无符号类型和一种整型类型之外,size of()返回的最大值大小几乎可以是任何大小。

    因此,用于某个大小的格式字符串可能因服务器而异。它应该总是有“U”,但可能是L或D或其他什么…

    一个技巧是将它强制转换为机器上最大的整型,确保转换过程中不会丢失,然后使用与此已知类型相关联的格式字符串。

        8
  •  3
  •   vitaut    9 年前

    这个 C++ Format 库提供了一种快速、可移植(且安全)的 printf 包括 z 修改器 size_t :

    #include "format.h"
    
    size_t a = 42;
    
    int main() {
      fmt::printf("%zu", a);
    }
    

    除此之外,它还支持类似于python的格式字符串语法并捕获类型信息,这样您就不必手动提供:

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

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

    免责声明 :我是这个图书馆的作者。