【问题标题】:Resolving conversion warnings with compound assignment operators使用复合赋值运算符解决转换警告
【发布时间】:2014-11-14 07:07:17
【问题描述】:

在我们公司,我们有一个使用-Wconversion 编译的策略,它会产生一些转换警告。虽然我同意这种额外的检查可以防止错误,但在以下情况下看到速记运算符的警告很烦人:

uint8_t byte;
byte += 8; // conversion to 'uint8_t' from 'int' may alter its value [-Wconversion]

现在可以通过将其重写为byte = (uint8_t)(byte+8) 来解决此问题,这反过来又会降低代码的可读性。

有没有更好的方法来做到这一点?

【问题讨论】:

  • 我认为在这种情况下,治疗(演员)比原因更糟糕。甚至this page 也说“Wconversion 是为特定用途而设计的”。因此,一直启用Wconversion 可能不值得。
  • -Wconversion 甚至没有被-Wall -Wextra -pedantic 启用,正是因为它几乎没有作为警告的价值(在特殊情况下)。我同意 user694733 的观点,即任何解决此警告的方法只会使代码变得更糟——无论是强制转换、显式转换还是使用 #pragma gcc diagnostic 括起来的代码(推送/忽略/弹出)。
  • 强制隐式提升会破坏类型系统,并通过使所有操作数为正确类型(如byte += uint8_t(8))来挫败所有试图消除警告的尝试。这与使 0 成为无法分配给 uint8_tint 的不幸机制相同,并且会导致有关有符号/无符号不匹配的警告(也与 x ? 0 : 1 的事物有关),除非你'你'所有文字。 0 到 127 应该与任何至少有 8 位的整数类型隐式兼容(即不会引发任何多余的警告),无论它是有符号还是无符号。
  • 在 C++ 中,你永远不需要 C 风格的强制转换,也不应该使用它,因为它几乎可以防止 all 类型检查。对于转换内置类型,更喜欢使用转换构造函数语法:uint8_t(8)
  • @DDrmmr 在 C++ 中,“转换构造函数语法”(也称为“函数式转换表达式”)与 C 风格的转换相同。应以同等措施避免这两种情况。请参阅en.cppreference.com/w/cpp/language/explicit_cast "2) 函数转换表达式 .... 完全等同于相应的 C 样式转换表达式。"

标签: c++ c gcc compiler-warnings implicit-conversion


【解决方案1】:

考虑您收到警告的原因,即整数常量8 的类型为int。 C 中的所有内容都必须升级为(签名)int,这是该语言众所周知的设计缺陷。

假设您有byte += 256;byte += -1;byte += function_that_returns_int();。所有这些都是潜在的严重错误,因此启用该警告当然是有意义的。

除了将操作结果转换为预期的类型uint8_t 之外,确实没有其他解决方法。这不一定是坏事,因为它会创建自记录代码,说“是的,我实际上已经考虑过在这个计算中使用了哪些类型,所以应该没有溢出”。

【讨论】:

  • 考虑 uint8_t b1 = 0, b2 = 1; b1 |= b2; 这仍然会给出警告,因为 b1 + b2 是 int 类型。我发现的唯一选择是要么不使用-Wconversion,要么永远不要在小于 int 的任何东西上使用复合运算符。不幸的是,我发现-Wconversion 有助于使错误更加明显,并有助于保持 API 的一致性。
  • @RyanB 这不是编译器的错,而是语言的错。对小整数类型的操作危险的。只需对您的示例进行细微的更改:b1 |= b2 - 2;,突然间我们已经签名并且到处都有负操作数。这就是为什么小型 8/16 位微控制器的 C 编程实际上比为高端 ARM 或 PC 编写大型程序需要更详细的语言知识的原因之一。
【解决方案2】:

这可能无法完全解决您的问题,但至少可以提示您几乎所有问题都有解决方案。

#include <stdio.h>
#include <stdint.h>

#define SAFE_ADD(a,b) ((a) = (typeof(a))((a)+(b)))

int main(void)
{
        uint8_t byte = 0;
        SAFE_ADD(byte, 8);

        fprintf(stderr, "byte = %d \n", byte);
        return 0;
}

使用 gcc 4.8.4 (gcc -Wall -Wconversion byte.c) 编译时没有警告
希望对您有所帮助。

【讨论】:

  • 现在用gcc -std=c11 -pedantic-errors -Wall -Wconversion byte.c编译。 typeof 是过时的非标准废话。请改用 C11 _Generic
  • 你错过了重点,没关系,看看上面的老 cmets,而不是找到一个合理的解决方案,他们说“告诉你的公司他们应该改变他们的政策......,你为什么使用-Wconversion 甚至不是警告,这个.. 那个..” 我所做的是我提出了一个示例(更像是模板)解决方案。您所说的可以通过编写实际类型(针对 typeof 的 uint8_t)并将宏重命名为 SAFE_ADD_UINT8 或您喜欢的任何内容轻松修复,而且我知道 typeof 也是 GCC 扩展,我个人不使用它。”
猜你喜欢
  • 1970-01-01
  • 2011-11-16
  • 1970-01-01
  • 2020-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-02
  • 2020-04-17
相关资源
最近更新 更多