【问题标题】:Warnings or errors for C++ implicit conversion of primitivesC++ 隐式转换原语的警告或错误
【发布时间】:2011-05-27 12:03:37
【问题描述】:

我对一些 C++ 代码进行了一些重度重构,并发现了许多由我不知道的隐式转换引起的错误。

示例

struct A *a();

bool b() {
    return a();
}

void c() {
    int64_t const d(b());
}

问题

  1. b 中,a 的返回类型被默默地转换为bool
  2. c 中,从b 返回的值被静默提升为int64_t

问题

我如何才能收到原始类型之间隐式转换的警告或错误

注意

  1. -Wconversion 的使用似乎只选择了几个与上述示例无关的任意转换。
  2. BOOST_STRONG_TYPEDEF 不是一个选项(我的类型需要是 POD,因为它们用于磁盘结构)。
  3. C 也很有趣,但是这个问题与 C++ 代码库有关。

【问题讨论】:

  • 我不知道 -Wextra 是否会警告这些,但通常如果您想获得更多诊断信息并在代码中找到更多有问题的地方,然后尝试在几个关闭扩展的编译器上构建它,所有警告都打开了。例如 gcc、icc 和 clang。你肯定会发现更多问题。
  • 你用的是什么版本的gcc?
  • 两种转换都符合标准,因此编译器不应警告它们。尝试使用静态代码分析器。另请参阅此(不幸关闭)问题的 cmets stackoverflow.com/questions/19306020/…
  • @Raxvan:任何版本。

标签: c++ gcc type-conversion implicit-conversion


【解决方案1】:

C++ programming language, 3rd edition,附录 C.6,即“隐式类型转换”中,Bjarne Stroustrup 将转换分类为 promotionsconversions:第一个“保留值” "(这是你的情况 2),第二个没有(情况 1)。

关于转换,他说“基本类型可以通过多种方式相互转换。在我看来,允许进行太多转换。”和“编译器可以警告许多有问题的转换。幸运的是,许多编译器实际上会这样做。”

另一边的

促销是安全的,似乎编译器不应该给他们一个警告。

编译器警告通常不是强制性的。通常在 C++ drafts and final ANSI documents 中会报告“实施者应发出警告”,其中建议:如果需要,您可以自行检查以获取更多信息。

已编辑:添加了 C++11 注释:

The C++ programming language, 4th edition 中,第3 版的附录已被报告并再次扩展为第10.5 节“隐式类型转换”。

与之前的考虑相同,C++11 更精确地定义了“缩小转换”并添加了 {}-initializer notation (6.3.5),截断会导致编译错误。

【讨论】:

    【解决方案2】:

    如果您使用 gcc,您是否尝试过 -Wall -Wextra 基本上检查此页面
    http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

    如果不是 GCC,请发布编译器详细信息。

    【讨论】:

      【解决方案3】:

      Microsoft Visual C++ 会针对从 A*bool 的缩小转换发出警告。

      See Compiler Warning C4800

      另一方面,促销并不是“危险”的转换,因为不可能丢失数据。

      编辑:演示

      C:\Users\Ben>copy con test.cpp
      bool f( void ) { return new int(); }
      ^Z
              1 file(s) copied.
      
      C:\Users\Ben>cl /c /W4 test.cpp
      Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
      Copyright (C) Microsoft Corporation.  All rights reserved.
      
      test.cpp
      test.cpp(1) : warning C4800: 'int *' : forcing value to bool 'true' or 'false' (
      performance warning)
      

      【讨论】:

      • 相当肯定警告仅适用于 int 和朋友,而不适用于指针,因为它们明确旨在检查 NULL。
      • @DeadMG:它不会出现在诸如ifwhile 语句之类的布尔上下文中,只有在实际从值生成bool 变量时才会出现。
      • long 升级到double 通常是悄悄允许的,但可能会丢失精度。
      【解决方案4】:

      据我了解,您无法控制之间的隐式转换 原始类型:它是由标准和任何兼容的 编译器只会默默地执行它。

      您确定像 BOOST_STRONG_TYPEDEF 这样的方法不适用于您的 问题?一个没有虚成员函数而只有一个原语的类 数据成员基本上无非是一种 POD 数据类型。你可以 只需遵循相同的方法,只允许转换为基础 原始类型;示例:

      #include <iostream>
      #include <stdexcept>
      
      struct controlled_int {
        // allow creation from int
        controlled_int(int x) : value_(x) { };
        controlled_int& operator=(int x) { value_ = x; return *this; };
        // disallow assignment from bool; you might want to use BOOST_STATIC_ASSERT instead
        controlled_int& operator=(bool b) { throw std::logic_error("Invalid assignment of bool to controlled_int"); return *this; };
      
        // creation from bool shouldn't happen silently
        explicit controlled_int(bool b) : value_(b) { };
      
        // conversion to int is allowed
        operator int() { return value_; };
      
        // conversion to bool errors out; you might want to use BOOST_STATIC_ASSERT instead
      
        operator bool() { throw std::logic_error("Invalid conversion of controlled_int to bool"); };
      
        private:
          int value_;
      };
      
      int main()
      {
        controlled_int a(42);
      
        // This errors out:
        // bool b = a;
      
        // This gives an error as well:
        //a = true;
      
        std::cout << "Size of controlled_int: " << sizeof(a) << std::endl;
        std::cout << "Size of int: " << sizeof(int) << std::endl;
      
        return 0;
      }
      

      【讨论】:

      【解决方案5】:

      您可以使用其中一种可用的静态分析工具、clint 或 C++ 等价程序,或市售工具之一。其中许多工具可以找出有问题的隐式转换。

      【讨论】:

        【解决方案6】:

        编写自定义 clang 插件来诊断您的问题。我们在 LibreOffice 代码中做了很多这样的事情。如果您想获得灵感,请访问我们的资源http://cgit.freedesktop.org/libreoffice/core/tree/compilerplugins/clang

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-07-23
          • 2019-11-29
          • 1970-01-01
          • 2017-08-25
          • 2020-01-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多