size_t除以int类型转换规则

size_t divided by int type conversion rules

当我用 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) ...;

或者编译器会正确地猜测我想使用无符号整数运算?

2 确实被视为 int,然后隐式转换为 size_t。在混合运算 size_t / int 中,无符号类型 "wins" 和有符号类型被转换为无符号类型,假设无符号类型至少与有符号类型一样宽。结果是无符号的,即 size_t 在您的情况下。 (详见 Usual arithmetic conversions)。

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

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

因此文字 2 将被转换为无符号类型。

就我个人而言,我认为将提升留给编译器而不是显式提升更好:如果您的代码曾经被重构并且 a 成为签名类型,那么 a / 2u 将导致 a 被提升为无符号类型,具有潜在的灾难性后果。

size_t sz = 11;

sz / 2 = 5

sz / (-2) = 0

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

来自"CS dummies"

  • C 标准保证 size_t 是无符号整数。
  • 文字 2 总是 int 类型。
  • "usual artihmetic converstions guarantee that whenever an unsigned and a signed integer of the same size ("rank") 被用作二元运算中的操作数,有符号的操作数被转换为无符号类型。

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

a/(size_t)2 > (size_t)0

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

Should I always carefully write 'u' literals

一些编码标准,尤其是 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.

的任何实现