【问题标题】:printf and %llu vs %lu on OS X [duplicate]OS X 上的 printf 和 %llu 与 %lu [重复]
【发布时间】:2012-12-28 18:15:15
【问题描述】:

可能重复:
how to printf uint64_t?

为什么在我的 64 位 Mac(我使用 Clang)上 uint64_t 类型是 unsigned long long 而在 64 位 Ubuntu 上 uint64_t 类型是 unsigned long

这让我很难让我的printf 调用在两种环境下都不发出编译器警告(甚至不工作)。

我可以尝试使用宏来尝试选择正确的字符串(#define LU 或者%llu%lu,并且在处理printf 字符串的过程中稍微丑化了一点)但在 Mac 上我有64 位字长(因此将定义 _LP64UINTPTR_MAX != 0xffffffff),但它仍将 long long 用于 64 位 int 类型。

// printf macro switch (for the uint64_t's)
#if UINTPTR_MAX == 0xffffffff 
   // 32-bit
#  define LU "%llu"
#else 
   // assume 64-bit
   // special case for OS X because it is strange
   // should actually check also for __MACH__ 
#  ifdef __APPLE__
#    define LU "%llu"
#  else
#    define LU "%lu"
#  endif
#endif

【问题讨论】:

    标签: c++ macos types integer long-integer


    【解决方案1】:

    答案是通过静态转换进行推广:

    some_type i = 5;
    printf("our value is: %llu", (unsigned long long)i);
    

    【讨论】:

      【解决方案2】:

      uint64_t 的底层类型可以是任何实现,只要它实际上是 64 位。

      显然,在 C++ 中,首选的解决方案是使用 iostreams 而不是 printf,因为这样问题就消失了。但是您始终可以将传递给printf 的值转换为始终正确的类型:

      printf("%llu", static_cast<unsigned long long>(value));

      【讨论】:

      • 嗯...把代码加长一点。
      【解决方案3】:

      已经在<cinttypes> 中为您定义了宏。试试

      printf("%"PRIu64, x);
      

      或者,更好的是,使用 C++ 功能,例如

      std::cout << x;
      

      这将为您的变量类型选择正确的

      【讨论】:

      • fatal error: 'cinttypes' file not found
      • 这是一个 C++11 头文件,所以它取决于你的编译器的兼容性。如果支持 C99,会有一个&lt;inttypes.h&gt;
      • 啊,好的,谢谢。我确实在 C++11 libc++ 中找到了该文件。好吧,希望这个 inttypes.h 标头也可以在我的其他平台上使用,这是我在问题中的代码 sn-p 的替换:#define LU "%"PRIu64
      • std::cout &lt;&lt; x; 语句不等同于 printf()。如果您编写等效的语句,您就会明白为什么人们仍然使用 printf() 来格式化数字。 :-)
      【解决方案4】:

      不幸的是,标准对这些类型的大小不是很具体......唯一的保证是sizeof(int) &lt;= sizeof(long) &lt;= sizeof(long long)

      您可以像您说的那样使用宏,或者您可以尝试使用 %zu%ju 用于打印出 size_tuintmax_t 类型(在 OS X 上都是 64 位,尚未测试在 Ubuntu 上)。我认为没有其他选择。

      【讨论】:

      • 我以前从未见过%zu%ju。这有多标准?
      • 它是标准的并且应该是完全可移植的。 cplusplus.com/reference/cstdio/printf
      • 哇哦。一定是错过了。
      • %zu 用于 size_t 数据类型,在不同平台上有所不同,因此您可以确保做出正确的解释。基本上是将 size_t 的格式设置为 unsinged。
      【解决方案5】:

      我相信其他人会告诉你使用 BOOST。所以为了提供一个不依赖于 BOOST 的解决方案:

      我经常遇到同样的问题,所以我放弃并编写了自己的辅助宏,这些宏输入 %s 而不是任何品牌的 %llu%lu 或其他。我还发现它有助于保持一个健全的格式字符串设计,并提供更好(和更一致)的十六进制和指针打印输出。有两个警告:

      1. 您无法轻松组合额外的格式参数(左/右对齐、填充等)——但您也无法使用 LU 宏真正做到这一点。

        李>
      2. 这种方法确实为格式化和打印字符串的任务增加了额外的开销。但是,我编写了性能关键型应用程序,除了 Microsoft 的 Visual C++ 调试版本(由于所有内部验证和损坏检查,分配和释放堆内存的时间比正常情况要长约 200 倍)之外,我没有注意到这是一个问题。

      这是一个比较:

      printf( "Value1: " LU ", Value2: " LU, somevar1, somevar2 );
      

      对比

      printf( "Value1: %s, Value2: %s", cStrDec(somevar1), cStrDec(somevar2) );
      

      为了让它工作,我使用了一组宏和模板,如下所示:

      #define cStrHex( value )        StrHex    ( value ).c_str()
      #define cStrDec( value )        StrDecimal( value ).c_str()
      
      std::string StrDecimal( const uint64_t& src )
      {
          return StrFormat( "%u%u", uint32_t(src>>32), uint32_t(src) );
      }
      
      std::string StrDecimal( const int64_t& src )
      {
          return StrFormat( "%d%u", uint32_t(src>>32), uint32_t(src) );
      }
      
      std::string StrDecimal( const uint32_t& src )
      {
          return StrFormat( "%u", src );
      }
      
      std::string StrDecimal( const int32_t& src )
      {
          return StrFormat( "%d", src );
      }
      
      std::string StrHex( const uint64_t& src, const char* sep="_" )
      {
          return StrFormat( "0x%08x%s%08x", uint32_t(src>>32), sep, uint32_t(src) );
      }
      
      std::string StrHex( const int64_t& src, const char* sep="_" )
      {
          return StrFormat( "0x%08x%s%08x", uint32_t(src>>32), sep, uint32_t(src) );
      }
      
      // Repeat implementations for int32_t, int16_t, int8_t, etc.
      // I also did versions for 128-bit and 256-bit SIMD types, since I use those.
      // [...]
      

      我的字符串格式化函数基于现在首选的直接格式化为 std::string 的方法,看起来像这样:

      std::string StrFormatV( const char* fmt, va_list list )
      {
      #ifdef _MSC_VER
          int destSize = _vscprintf( fmt, list );
      #else
          va_list l2;
          va_copy(l2, list);
          int destSize = vsnprintf( nullptr, 0, fmt, l2 );
          va_end(l2);
      #endif
          std::string result;
          result.resize( destSize );
          if (destSize!=0)
                  vsnprintf( &result[0], destSize+1, fmt, list );
          return result;
      }
      
      std::string StrFormat( const char* fmt, ... )
      {
          va_list list;
          va_start( list, fmt );
          std::string result = StrFormatV( fmt, list );
          va_end( list );
      
          return *this;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-27
        • 2013-08-29
        • 2016-05-20
        • 2011-08-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多