【问题标题】:narrowing conversion from int to long unsigned int {} is ill-formed in C++11从 int 到 long unsigned int {} 的缩小转换在 C++11 中是不正确的
【发布时间】:2014-02-11 23:48:24
【问题描述】:

当我运行以下代码时 - 我收到警告“从 int 到 {} 内的 long unsigned int 的缩小转换在 C++11 [-Wnarrowing] 中格式错误。我使用的是 GNU 4.8 编译器。

typedef struct TableEntry
{
    unsigned long value;
    const char *label;
} TableEntry;

enum FunctionType
{
    NORMAL   = 0, 
    RANGE    = 1
};


TableEntry functionTypes[] = 
{
    {NORMAL,   "NORMAL"},
    {RANGE, "RANGE"}
};

我不明白为什么编译器将枚举视为 int?
这是 GCC 4.8 中的错误吗?有什么解决方法吗? 任何帮助表示赞赏。

【问题讨论】:

  • 我相信枚举总是被视为ints 幕后。如果您不指定枚举值的值,它们默认为 0、1、2,... 在这种情况下,您应该可以使用隐式转换,因为转换不应该花费您任何准确性。
  • 我们在每个文件中都有这些警告。大约 150 个文件。我的老板不喜欢看到这些警告。
  • 这是有效的 C++03 代码,因此 g++ 的警告很可能是没有根据的。如果 C++11 标准彻底破坏了 C++03 代码,那确实值得注意。也就是说,这只是 number 值不使用无符号整数的另一个原因。
  • 只要您确定隐式转换不会给您带来任何问题,您可以暂时禁用警告。但我真的不建议将其作为长期解决方案,因为启用该警告可能会在其他数据转换场景中为您省去麻烦。
  • 枚举 FunctionType : unsigned long { /* etc */ };这是向后做的,请修复结构声明。

标签: c++ c c++11 gcc-warning gcc4.8


【解决方案1】:

如果可行的话:

enum FunctionType
{
    NORMAL   = 0, 
    RANGE    = 1
};

typedef struct TableEntry
{
    FunctionType value;
    const char *label;
} TableEntry;


TableEntry functionTypes[] = 
{
    {NORMAL,   "NORMAL"},
    {RANGE, "RANGE"}
};

否则,将结构中的类型更改为int,或显式地将枚举基于与结构中相同的类型。

顺便说一句,我认为 g++ 警告是没有根据和错误的,因为原始代码是有效的 C++03。 更正: 据我现在理解,诊断是正确的,这是 C++11 中的一个重大变化。我简直不敢相信。


关于命名约定:那些全大写的标识符对于 Java 程序员(他们习惯于该约定)来说是好的,但在 C++ 中它们增加了无意中文本替换的机会。还有审美方面的考虑。在为宏保留全部大写方面取得了很大的成功。

【讨论】:

  • 您能否指出这是 c++11 中的重大变化的信息来源?
  • @Dave:问题中的代码就是一个例子。与 C++03 一样好,与 C++11 一样无效。这就是“破坏”的意思,它破坏了现有的代码。
【解决方案2】:

通常,无作用域枚举的底层类型是 int(它可以是任何可以表示枚举数的所有值的整数类型)。

但是我没有看到任何缩小转换,因为 unsigned long 类型可以表示 int 类型的所有值。

编辑:看来我错了,因为我在标准中发现了一个与我的假设相矛盾的例子

unsigned int ui1 = {-1}; // error: narrows

所以 unsigned int 不能使用包含负数的初始化列表来初始化。

所以为了避免警告,枚举可以写成

enum FunctionType : unsigned int // or unsigned long
{
    NORMAL   = 0, 
    RANGE    = 1
};

【讨论】:

  • int 可以取负值,而 unsigned long 不能。因此缩小转化率
  • 大约一半的int 值不能表示为unsigned long
  • @srinivas 所有 int 类型的值(包括负数)都可以用 unsigned long 类型表示。 unsigned long 类型是 int 和 unsigned long 的常用类型。
  • @ 干杯和hth。 - Alf 据我了解,标准的所有 int 值(包括负数)都可以用 unsigned long 类型表示。
  • @Cheers 和 hth。 - Alf 看来你是对的。我已经更新了我的帖子。
【解决方案3】:
  • 您可以将“值”更改为 int
  • 或者您可以使用强类型的新“枚举类”(c++11),并将您的“值”声明为这种类型。

【讨论】:

  • 感谢您的建议。我在大约 150 个文件中收到了这些警告。有更好的方法吗?
  • 有趣的是,我的前两个建议是:将value 的类型更改为FunctionType,或者使FunctionType 支持unsigned long
【解决方案4】:

由于您使用的是 c++11,您可以像这样声明您的枚举:
enum Enum2 : unsigned char;
这应该迫使枚举工作。也就是说,IDEONE 对您发布的代码没有警告/错误。可能只是 GCC 过于迂腐。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-02
    • 2016-12-20
    • 2020-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多