C++ 的警告或错误原语的隐式转换

发布于 2024-10-08 13:31:14 字数 701 浏览 7 评论 0原文

我对一些 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++ 代码库有关。

I've done some heavy refactoring of some C++ code, and discovered numerous bugs arising from implicit conversions that I'm not aware of.

Example

struct A *a();

bool b() {
    return a();
}

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

Issues

  1. In b, the return type of a is silently cast to bool.
  2. In c, the value returned from b is silently promoted to int64_t.

Question

How can I receive warnings or errors for the implicit conversion between primitive types?

Note

  1. The use of -Wconversion seems to only pick up several arbitrary conversions unrelated to the example above.
  2. BOOST_STRONG_TYPEDEF is not an option (my types need to be PODs, as they're used in disk structures).
  3. C is also of interest, however this problem pertains to a C++ code base.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

梦途 2024-10-15 13:31:14

C++编程语言,第3版,附录C.6,即“隐式类型转换”中, Bjarne Stroustrup 将转化分为促销转化:第一个转化“保留价值”(即案例 2),第二个转化则不然(案例 1)。

关于转换,他说“基本类型可以通过多种令人眼花缭乱的方式相互转换。在我看来,太多的转换是被允许的。”和“编译器可以警告许多有问题的转换。幸运的是,许多编译器确实这样做了。”

另一方面,促销是安全的,编译器似乎不应该向它们发出警告。

编译器警告通常不是强制性的。通常在 C++ 草案和最终 ANSI 文档 中,报告“实现者应该发出警告”,其中建议:如果需要,您可以自行检查以获取更多信息。

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

C++ 编程语言,第 4 版 中,附录第三版已再次报告并扩展为第 10.5 节“隐式类型转换”。

由于前面的考虑因素相同,C++11 更精确地定义了“缩小转换”并添加了 {} 初始化符号 (6.3.5),使用该符号截断会导致编译错误。

In the C++ programming language, 3rd edition, appendix C.6, namely "Implicit Type Conversion", Bjarne Stroustrup classifies conversions as promotions and conversions: the first ones "preserve values" (that's your case 2), the second ones doesn't (case 1).

About conversions, he says that "The fundamental types can be converted into each other in a bewildering number of ways. In my opinion, too many conversions are allowed." and "A compiler can warn about many questionable conversions. Fortunately, many compilers actually do."

promotions on the other side are safe, and it seems like a compiler is not supposed to give a warning for them.

Compiler warnings are usually not mandatory. Usually in the C++ drafts and final ANSI documents it is reported that "implementers should issue a warning" where suggested: you can check it yourself for further information if needed.

EDITED: added C++11 note:

In The C++ programming language, 4th edition, the appendix of the 3rd edition has been reported and extended as section 10.5, "Implicit Type Conversion" again.

Being the previous considerations the same, C++11 more precisely define "narrowing conversions" and adds up the {}-initializer notation (6.3.5), with which truncations lead to a compilation error.

脸赞 2024-10-15 13:31:14

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

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

If you are using gcc have you tried -Wall -Wextra basically check this page
http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

If it is not GCC please post the compiler details.

堇年纸鸢 2024-10-15 13:31:14

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

请参阅编译器警告 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)

Microsoft Visual C++ would give a warning about the narrowing conversion from A* to bool.

See Compiler Warning C4800

Promotion on the other hand is not a "dangerous" conversion, because it's impossible to lose data.

EDIT: Demonstration

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)
吐个泡泡 2024-10-15 13:31:14

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

您确定像 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;
}

As far as I understand, you cannot control implicit conversion between
primitive types: it's mandated by the standard and any compliant
compiler will just perform it silently.

Are you sure an approach like BOOST_STRONG_TYPEDEF won't work in your
problem? A class with no virtual member functions and just one primitive
data member is basically nothing more than a POD data type. You can
just follow the same approach and only allow conversion to the base
primitive type; example:

#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;
}
靖瑶 2024-10-15 13:31:14

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

You can use one of the available static analysis tools, programs like clint or C++ equivalents, or one of the commercially available tools. Many of these tools can pick out problematic implicit conversions.

红颜悴 2024-10-15 13:31:14

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

Write a custom clang plugin to diagnose your problems. We do a lot of this in the LibreOffice code. Come browse our source if you want inspiration at http://cgit.freedesktop.org/libreoffice/core/tree/compilerplugins/clang

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文