g ++警告:从int转换为uint16_t可能会改变其值

时间:2017-11-29 00:21:15

标签: c++ g++

根据高级别SO用户的建议,我最近开始使用代码库中的-Wconversion标志进行编译。这已经产生了很多警告,其中一些是合法的(例如,不必要地添加signedunsigned类型),但也有一些头颅,如下所示:

#include <cstdint>

int main()
{
  uint16_t a = 4;
  uint16_t b = 5;

  b += a;

  return 0;
}

当我使用g++ -Wconversion -std=c++11 -O0 myFile.cpp进行编译时,我得到了

warning: conversion to 'uint16_t {aka short unsigned int}' from 'int' may alter its value [-Wconversion]
    b += a;
      ^

我已经在SO上讨论了一些类似的问题(处理|<<运算符),看了here,并阅读了数字促销和数字转化部分here。我的理解是,为了进行数学计算,ab被提升为int(因为那是第一种可以适合整个uint16_t的类型值范围),执行数学,结果被写回...除了数学结果是int,并将其写回uint16_t生成警告。其他问题的共识基本上就是抛弃了警告,我唯一知道如何做到这一点的方法是b = (uint16_t)(b + a);(或等效的b = static_cast<uint16_t>(b + a);)。

不要让这个问题过于宽泛,但假设我对整数促销的理解是正确的......

  1. 处理这种前进的最佳方法是什么?我应该避免对比int更窄的类型进行数学运算吗?对我来说似乎很奇怪,我必须转换一个与所有操作数相同类型的算术结果(我希望编译器能够识别并抑制警告)。从历史上看,我不想使用比我需要的更多的位,只需让编译器根据需要处理促销/转换/填充。
  2. 有人经常使用-Wconversion标志吗?在我自己使用它几天之后,我开始认为它的最佳用例是打开它,查看它抱怨的内容,修复合法的投诉,然后将其关闭。或者也许是我对合法投诉的定义&#34;需要重新调整。用拼写出来的演员替换我的所有+=运算符似乎比任何事都更令人讨厌。
  3. 我也很想将此标记为c,因为使用c编译的等效gcc -Wconversion -std=c11 -O0 myFile.c代码会产生完全相同的警告。但就是这样,我在x86_64 Fedora 23盒子上使用g++版本5.3.1。如果我错过了,请指出我的欺骗行为;如果这里唯一的答案/建议是抛弃警告,那么这就是一个骗局。

2 个答案:

答案 0 :(得分:4)

  

处理这种前进的最佳方法是什么?

-Wno-conversion

或者只是不指明。不过,这只是一种意见。

根据我的经验,对窄整数运算的需求往往很少,因此您仍然可以为项目保留它,并禁用发生此无用警告的少数情况。但是,这可能在很大程度上取决于您的项目类型,因此您的体验可能会有所不同。

  

我应该避免对比int更窄的类型进行数学运算吗?

通常是;除非您有特定的理由使用它们。 “我不需要额外的位”在我看来并不是一个特定的理由。无论如何,算术操作数被提升为int,并且使用int通常更快,更不容易出错。

  

在我自己使用它几天之后,我开始认为它的最佳用例是打开它,查看它抱怨的内容,修复合法的投诉,然后将其关闭。

对于警告标记,这通常是一种有用的方法,它既不包含-Wall也不包含-Wextra,例如-Wsuggest-前缀的标记。有一个原因,他们不包括在“所有警告”中。

答案 1 :(得分:3)

我认为这可以被认为是gcc的缺点。

由于此代码未生成任何警告:

int a = ..., b = ...;

a += b;

此代码也不应该生成,因为在语义上它们是相同的(添加了两个相同类型的数字,并将结果放入相同类型的变量中):

short a = ..., b = ...;

a += b;

但GCC会发出警告,因为正如您所说,short会被提升为int。但是short版本与int版本相比并不危险,因为如果添加溢出,那么行为是针对short情况的实现定义的,并且对于int情况未定义(或者如果使用无符号数字,则在两种情况下都可能发生截断)。

Clang更智能地处理这种情况,并不会对此案例发出警告。我认为这是因为它实际上跟踪了结果的可能位宽(或可能是范围?)。因此,例如,这会警告:

int a = ...;
short b = a;

但这并不是(但GCC警告说):

int a = ...;
short b = a&0xf; // there is a conversion here, but clang knows that only 4 bits are used, so it doesn't warn

因此,在GCC具有更智能-Wconversion之前,您的选择是:

  1. 请勿使用-Wconversion
  2. 修复它打印的所有警告
  3. 使用clang代替(可能是GCC:关闭此警告;而对于clang:将其打开)
  4. 但不要屏住呼吸,直到它被修复,有一个bug关于此,于2009年开放。

    注意:

      

    从历史上看,我不想使用比我需要的更多的位,只需让编译器根据需要处理促销/转换/填充。

    如果您使用较短的类型进行存储,那就没问题了。但通常情况下,没有理由使用比int更短的类型来进行算术运算。它没有加速(即使它可能更慢,因为不必要的掩码)。