【问题标题】:size_t divided by int type conversion rulessize_t 除以 int 类型转换规则
【发布时间】:2015-08-16 10:12:51
【问题描述】:

当我使用 size_t 类型(或 unsigned long)进行算术运算时,我应该多小心使用类型文字装饰整数常量。例如,

size_t a = 1111111;
if (a/2 > 0) ...;

当编译器进行除法时会发生什么?它将 2 视为整数还是无符号整数?如果是前者,那么 (unsigned int)/(int) 的结果类型是什么?

我是否应该一直小心地写 'u' 字面量

if (a/2u > 0) ...;
for (a=amax; a >= 0u; a -= 3u) ...;

或者编译器会正确地猜到我想对无符号整数使用操作?

【问题讨论】:

  • 为什么不简单地a / (size_t)2
  • @Eregrith:因为它并不“简单”。这既困难又丑陋。
  • 阅读integral conversions 可能会对您有所帮助。
  • @AnT 有什么难的?将 2 转换为 size_t?
  • @Eregrith:使用显式类型名称轻松实现类型无关的杂乱代码是很困难的,至少因为它让人跨越了“丑化”代码的心理障碍。最重要的是,输入整个 (size_t) 后缀就足够了,它产生的热量多于光。

标签: c++ c type-conversion literals


【解决方案1】:
  • C 标准保证size_t 是无符号整数。
  • 文字 2 始终是 int 类型。
  • “通常的算术转换保证,只要将相同大小(“秩”)的无符号整数和有符号整数用作二进制运算中的操作数,有符号操作数就会转换为无符号类型。

所以编译器实际上是这样解释表达式的:

a/(size_t)2 > (size_t)0

> 运算符或任何关系运算符的结果始终是 int 类型,但作为该组运算符的特殊情况。)

我是否应该一直小心地写 'u' 字面量

一些编码标准,尤其是 MISRA-C,会让您这样做,以确保代码中不存在隐式类型提升。隐式提升或转换非常危险,而且它们是 C 语言的一个缺陷。

对于您的具体情况,隐式促销没有真正的危险。但在某些情况下,使用小整数类型时,您可能会因为隐式类型提升而意外更改符号。

显式没有任何害处,尽管在​​代码中为每个字面量编写 u 后缀可能会降低可读性。

现在,作为 C 程序员,要处理类型提升的危险,您真正必须做的是了解整数提升和通常的算术转换是如何工作的 (here's some example on the topic)。可悲的是,有很多 C 程序员不这样做,包括退伍军人。结果是微妙的,但有时是严重的错误。特别是在使用移位等按位运算符时,符号的变化可能会引发未定义的行为。

这些规则可能有些难以学习,因为它们的行为并不合理或始终如一。但在您详细了解这些规则之前,您必须明确类型。


编辑:为了挑剔,size_t 的大小实际上没有指定,所有标准都说它必须足够大以至少容纳值 65535(2 个字节)。所以理论上,size_t 可能等于unsigned short,在这种情况下,促销活动会完全不同。但在实践中,我怀疑这种情况是否有任何意义,因为我不相信存在任何size_t 小于unsigned int 的实现。

【讨论】:

  • 我不同意所有这些,但这是一个很好的答案,再加上一个。
  • 对比的结果还是int,但这可能不是你的意思……
  • @JensGustedt 啊,是的,> 运算符是其中一种特殊情况,我将进行编辑。谢谢。
  • 顺便说一句,应该注意的是 MISRA-C 规则要求您在每个整数文字上写一个 u 后缀,这可能是所有这些规则中最受争议和质疑的 MISRA 规则。因为在大多数情况下 u 后缀只会使代码变得混乱,尤其是在编写十六进制文字时,因为无论如何这些都保证是无符号的。
【解决方案2】:

2 确实被视为int,然后隐式转换为size_t。在混合操作size_t / int 中,无符号类型“胜出”并且有符号类型转换为无符号类型,假设无符号类型至少与有符号类型一样宽。结果是无符号的,即 size_t 在您的情况下。 (详见Usual arithmetic conversions)。

最好将其写为a / 2。没有后缀,没有类型转换。尽可能保持代码与类型无关。类型名称(和后缀)属于声明,而不是语句。

【讨论】:

    【解决方案3】:
    size_t sz = 11;
    
    sz / 2 = 5
    
    sz / (-2) = 0
    

    为什么? sz 被视为无符号整数,因为大小不能为负数。使用无符号 intint 进行算术运算时,int 会变成 unsigned int

    来自“CS 傻瓜”

    【讨论】:

      【解决方案4】:

      C++ 和 C 在评估像除法这样的运算符时都将有符号类型提升为无符号类型,该运算符有两个参数,其中一个参数是无符号类型。

      所以文字 2 将被转换为无符号类型。

      就我个人而言,我认为将提升留给编译器而不是明确表示更好:如果您的代码曾经被重构并且a 成为有符号类型,那么a / 2u 将导致a 被提升为无符号类型,可能带来灾难性的后果。

      【讨论】:

      • 将你的类型从 size_t 更改为有符号类型是危险的做法。这不是 2u 文字的错。因为您怀疑将来某些猴子会维护代码而省略显式类型,这听起来不像是一个有效的理由。
      • 所涉及的类型排名。如果它是int/unsigned char 的除法,那么通常int 的商不是unsigned char 首先提升为int 吗?
      • @chux 是的,但是这有什么关系,因为 C 中没有字符类型的文字?
      • @Lundin:在纽约市工作了十多年;有很多重构猴子;-)
      • @Bathsheba 我不认为你可以让代码防猴子。如果不知道自己在做什么的人来更改代码,那么原始程序员的编码实践将无法挽救程序。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-29
      • 1970-01-01
      • 1970-01-01
      • 2013-03-05
      • 1970-01-01
      相关资源
      最近更新 更多