【问题标题】:How to do portable 64 bit arithmetic, without compiler warnings如何在没有编译器警告的情况下进行可移植的 64 位算术
【发布时间】:2011-04-30 09:04:35
【问题描述】:

我偶尔会在我的一个开源 C++ 库中使用 64 位算术。我发现long long 非常适合我的目的。甚至一些有 10 年历史的 solaris 盒子也可以编译它。并且它也可以在 Windows 上使用 #defines 来工作。

现在的问题是我收到了用户的抱怨,因为他们使用 GCC -pedantic 设置进行编译,而 GCC 坚持发出警告,指出 long long 不是 C++ 标准的一部分。这可能是对的,但我对 C++ 标准本身并不太感兴趣,我只是希望我的代码能够在尽可能多的编译器上工作。

所以我的问题是双重的:

  • 谁能说出不支持 64 位 long long 的实际 C++ 编译器?
  • 有没有办法让 GCC 编译 64 位算术(在 32 位平台上)而没有编译器警告? (stdint.h 没有帮助,因为它还取决于 long long

附:

如果有平台的 long long 变成 128 位或更大,这很有趣,但对我来说不是问题。

【问题讨论】:

  • 使用 -pedantic 是完成no工作并无缘无故阻止使用大多数第三方库的好方法。这就是它在罐头上所说的 - 毫无意义的抱怨,但我认为告诉你的用户不要再傻了也会让他们喜欢你!?
  • @Clifford:-pedantic 可以帮助您编写将来易于移植到其他编译器的代码。如果您对此不担心,则不必使用它,但您最终将成为编写所有第三方库的人,这些库 (a) 会产生奇怪的警告,并且 (b) 很可能不会不适用于某些编译器。诚然,long long 不是最有可能的真正问题,但我曾经从事便携式产品的工作,并且有几次我们从 Windows 男孩那里修复了实际上在我们的某些平台上不起作用的东西(而 gcc -pedantic 会已经告诉他们了)。
  • ...奇怪的是,当 linux 程序员在产品的可移植组件上工作时,他们的代码不太可能在其他平台上通过测试。
  • @Steve:我认为您应该在所问问题的上下文中看到 Clifford 的评论,并且 100% 便携并不是这里的目标。
  • 我知道您自己不需要它,问题是您的用户为什么使用-pedantic。克利福德认为没有任何理由,因为他认为迂腐的警告是没有意义的,而且你的用户很傻。我怀疑这个分析有几个方面:-)

标签: c++ gcc portability


【解决方案1】:

在 GCC 中,使用 -Wno-long-long 编译器选项来抑制该特定警告。

您也可以使用-std=C++0x,但可能会进一步降低可移植性。

【讨论】:

  • 我真的希望它可以在没有命令行开关的情况下修复,但无论如何,谢谢。
【解决方案2】:

您可以使用-Wno-long-long 使警告静音(确保它出现在-pedantic 之后)。 C99 需要 64 位整数,我认为 C++0x 也是如此,因此现在没有它们的编译器越来越少。

【讨论】:

  • 我认为 C99 不需要 long long 支持,但我认为 C++0x 需要它。
  • 我 100% 确定它在 C99 中,但我很确定它不在 C++98 中。 (当时这是一笔巨大的交易,因为微软强迫委员会接受“sizeof(size_t) > sizeof(long)”作为合法的 ABI 选项,而 C89 承诺永远不会发生这种情况。)
【解决方案3】:

您可以使用众多 C++ bigint 库之一替换您对 long long 的使用。我确信其中一些避免了这个编译器错误。就个人而言,我宁愿坚持错误。

【讨论】:

    【解决方案4】:

    如果您无法控制传递给 gcc 的开关,您可以使用 #pragma 关闭警告。

    http://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html

    【讨论】:

      【解决方案5】:

      当您的库作为源提供时,一种选择是提供“移植”标头,您的用户有责任在其中提供 64 位类型(您需要指定名称)。然后,他们自然也有责任处理他们选择的类型引发的任何编译器警告,要么避免它们,要么抑制它们,要么忽略它们。

      我想这就是你所说的“搞乱#defines”,但我认为这并没有太大的问题。您可以提供一个默认版本,直接使用long long,并且可以在您使用了 10 年的 Solaris 机器和 Windows 上运行,因此大多数用户永远不需要靠近您的库的用户可配置部分。

      那么对于学究气的用户,您可以提供包含<sys/types.h> 的GCC 版本,并使用int64_t 而不是long longg++ -pedantic 不会对我产生任何警告。您甚至可以通过识别 GCC 在默认版本中执行此操作,这肯定会与 #defines 混淆,但对于多平台产品来说,这又不是一种不寻常的方式。

      如果您的库也作为特定平台的二进制文件提供,那么您当然必须确定 64 位类型将是什么。如果它也出现在库接口中(因此也出现在头文件中),那么您只需选择一个不会通过合理的编译器选项引发任何警告的选项。我认为-pedantic 是一个合理的编译器选项,显然您的用户也是如此,所以这又是 GCC 上的int64_t

      【讨论】:

      • 我确实有一个 config.h。在某个时间点,我已经在使用int64_t(来自stdint.h),但放弃了它,转而使用long long,因为后者得到了更广泛的支持。有趣的是int64_t(来自stdint.h)确实有效,即使它是long long(在我的系统上)的typedef。打败了我,但感谢你让我走上正轨。
      • @jdv:那是因为 Void 提到的事情:GCC 的标头在我的机器上使用 __extension__,在 /usr/include/sys/_types.h
      • 到目前为止,我用 mingw 进行了测试,发现 sys/types.h 没有定义 int64_t。它从<stdint.h> 获取它,并且不使用extension。好吧,它有效,这对我很重要....
      • @jdv:哦,好吧,那我有点困惑。我实际上并没有检查/usr/include/sys/_types.h 是否是为我通常的编译定义的int64_t:我在cygwin 下安装了至少三个版本的gcc,因此该文件可能来自其他文件之一或可以不被使用。可能只是 GCC 隐藏了某些标头生成的所有弃用/扩展警告。
      【解决方案6】:

      您还可以使用 gcc 的“__extension__”功能抑制警告,例如:

      // No '-pedantic' warning/error.
      __extension__ long long foo = 2;
      
      // Exhibits '-pedantic' warning/error.
      long long bar = 3
      

      然后编译:

      $ g++ -pedantic -fsyntax-only foo.cpp
      foo.cpp:5: error: ISO C++ 1998 does not support 'long long'
      

      请注意,只有最后一次使用 long long 会触发 -pedantic 错误,因为没有预先添加 __extension__。无论如何,我会选择@Steve Jessop's suggestion,而不是使用int64_t

      【讨论】:

        【解决方案7】:

        如果你在系统包含目录中有Boost,你可以说

        #include "boost/cstdint.hpp"
        boost::int64_t my_64_bit_number;
        

        如果它位于系统包含目录中,则会自动抑制警告。

        【讨论】:

        • 我不会使用这个建议,因为我还没有使用 boost。不过谢谢。
        猜你喜欢
        • 2022-07-20
        • 2011-12-22
        • 2018-01-29
        • 2015-09-24
        • 1970-01-01
        • 1970-01-01
        • 2012-07-18
        • 1970-01-01
        • 2011-01-21
        相关资源
        最近更新 更多