【问题标题】:Strange GCC short int conversion warning奇怪的 GCC short int 转换警告
【发布时间】:2013-11-27 07:38:49
【问题描述】:

我有一点 C 代码,完全是这样的:

short int fun16(void){
    short int a = 2;
    short int b = 2;
    return a+b;
}

当我尝试使用 GCC 编译它时,我收到警告:

warning: conversion to 'short int' from 'int' may alter its value [-Wconversion]
  return a+b;
          ^

虽然没有可见的转换。两个操作数都很短,甚至返回值也很短。那么,有什么收获呢?

【问题讨论】:

    标签: c gcc implicit-conversion


    【解决方案1】:

    当您进行算术计算时,操作数受制于“通常的算术转换”(Acme's answer 中引用的“整数提升”的超集——他打败了我,但我还是会继续发布: -))。这些将short int 扩展为普通的int,所以:

    a + b
    

    计算相同的结果:

    ((int) a) + ((int) b)
    

    return 语句必须将这个int 缩小为short int,这就是 gcc 产生警告的地方。

    【讨论】:

      【解决方案2】:

      引用标准(§6.3.1.1 ¶2):

      无论intunsigned int 可以在表达式中使用以下内容 使用:

      • 具有整数类型(intunsigned int 除外)的对象或表达式,其整数 转化排名小于等于intunsigned int的排名。
      • _Boolintsigned intunsigned int 类型的位字段。

      如果int 可以表示原始类型的所有值,则该值为 转换为int;否则,它将转换为unsigned int。 这些称为整数促销。所有其他类型都是 整数促销保持不变。

      -Wconversion 标志警告:

      警告可能会改变值的隐式转换。这包括 实数和整数之间的转换,例如 abs (x)xdouble 时; 有符号和无符号之间的转换,例如 unsigned ui = -1; 和 转换为较小的类型,例如 sqrtf (M_PI)。不要警告 像 abs ((int) x)ui = (unsigned) -1 这样的显式转换,或者如果 值不会被abs (2.0) 中的转换改变。警告 关于有符号和无符号整数之间的转换可以禁用 通过使用-Wno-sign-conversion

      【讨论】:

        【解决方案3】:

        来自C 编程语言部分2.7 类型转换

        • 如果任一操作数为long double,则将另一个转换为long double
        • 否则,如果任一操作数为double,则将另一个转换为double
        • 否则,如果任一操作数为float,则将另一个转换为float
        • 否则,将charshort 转换为int
        • 然后,如果任一操作数为long,则将另一个转换为long

        【讨论】:

        • ISO C 中的实际规则不同
        【解决方案4】:

        当两个操作数都是short 时,它们在算术运算中被隐式提升为int

        【讨论】:

          【解决方案5】:

          如果一个int可以表示原始类型的所有值,则将该值转换为一个int;否则,它将转换为无符号整数。这些被称为整数促销。整数提升不会改变所有其他类型。

          参考以下帖子: Why must a short be converted to an int before arithmetic operations in C and C++?

          【讨论】:

          • 欢迎来到 Stack Overflow。请尽快阅读About 页面。我不太清楚你的答案除了可能的重复之外还没有添加什么。诚然,作为一个新手,你还不能离开 cmets,但这是一个相当古老的问题,它突然变得活跃起来。要为此类问题添加答案,您通常需要一些重要的新信息。
          【解决方案6】:

          GCC 只会对生成临时变量的操作执行这些隐式升级为 int:

          ++i
          i += 2
          

          不会生成临时文件。

          i = j + 1
          

          会的。

          以下代码:

          std::cout << sizeof(i) << " "
          << sizeof(i + 1) << " " 
          << sizeof(i + static_cast<unsigned short>(1)) << " " 
          << sizeof(static_cast<unsigned short>(i) + static_cast<unsigned short>(1)) << " " 
          << sizeof(++i) << " " 
          << sizeof(i + 0x0F) << " " 
          << sizeof(i += 1) << std::endl;
          

          将在发布或调试模式下提供以下输出: 2 4 4 4 2 4 2

          表明虽然有些事情可能会抑制警告,但它们实际上并没有阻止编译器升级为 int。 因此,要丢失警告,请停止生成临时对象。

          【讨论】:

          • i += 2 表示i = i + 2。如托雷克的回答所述,右侧经历了整数提升。 ++i 表示具有类似行为的 i += 1
          • 不,它不接受该促销活动。看看输出......我很清楚它们扩展到什么。
          • 参见 C11 6.5.16.2 “E1 op= E2 形式的复合赋值等效于简单赋值表达式 E1 = E1 op (E2),除了左值 E1 仅计算一次”。因此i += 2i = i + 2 完全相同。
          • 我只是说他们是一样的,你这个傻瓜。如果您看不懂,请不要回复。
          • 你说“它没有经历那种提升”。但确实如此;你的回答说i += 2 的行为与i = i + 2 不同(这是错误的,因为我们同意这两者是相同的)
          猜你喜欢
          • 2012-03-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多