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
被视为无符号整数,因为大小不能为负数。当用无符号 int
和 int
进行算术运算时,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
.
的任何实现
当我用 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
被视为无符号整数,因为大小不能为负数。当用无符号 int
和 int
进行算术运算时,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
.