C 类型升级/转换
sizeof运算符的结果似乎是size_t类型,在Windows 64位上定义为无符号long long 考虑以下一段(伪)代码: 当按如下方式调用func时,在类型提升/转换方面实际会发生什么C 类型升级/转换,c,64-bit,C,64 Bit,sizeof运算符的结果似乎是size_t类型,在Windows 64位上定义为无符号long long 考虑以下一段(伪)代码: 当按如下方式调用func时,在类型提升/转换方面实际会发生什么 func((herp + derp) * durr * sizeof wut); // 1st example herp、derp和durr的值是否首先提升为无符号长长度,然后在计算结果后,将结果转换回无符号长长度 func((herp + derp) * durr * (unsigned long)
func((herp + derp) * durr * sizeof wut); // 1st example
herp、derp和durr的值是否首先提升为无符号长长度,然后在计算结果后,将结果转换回无符号长长度
func((herp + derp) * durr * (unsigned long)sizeof wut); // 2nd example
相反,当按如下方式调用func时,是否唯一将类型转换为unsigned long的转换
func((herp + derp) * durr * (unsigned long)sizeof wut); // 2nd example
考虑到类型转换/升级,调用func最合适/正确的方法是什么?当遇到参数大小不同的算术运算符时,编译器应用,这基本上使两个操作数的类型相同 这在整个表达式中执行,一次一个运算符。根据C的语法将表达式分析为单独的操作;编译器不允许修改解析,除非它能证明结果没有差别(在这种情况下,修改或多或少是不相关的) 请考虑你的表达:
func((herp + derp) * durr * sizeof wut);
这在语法上等同于以下一系列操作,其中省略了类型和转换(目前):
前四个临时变量将自动键入每个运算符的结果类型(这是该运算符的常用算术转换生成的类型)
temp1=herp+derp代码>
herp
和derp
都是unsigned long
;不需要转换;结果类型为无符号长
temp2=temp1*durr代码>
temp1
和durr
都是unsigned long
;不需要转换;结果类型为无符号长
temp3=wut的大小代码>
sizeof
始终返回size\t
,因此这是结果的类型
temp4=temp2*temp3
temp2
是unsigned long
,temp3
是size\u t
,在示例平台上是unsigned long
。这需要将temp2
转换为unsigned long
,之后的结果类型为unsigned long
unsigned long temp1 = herp + derp;
unsigned long temp2 = temp1 * durr;
unsigned long long temp3 = sizeof wut
unsigned long long temp4 = (unsigned long long)temp2 * temp3;
temp5 = (unsigned long)temp4;
func(temp5)
这里需要说明的关键是,结果将转换为其他类型这一事实对其计算没有影响。编译器不能决定不应用通常的算术转换,或应用不寻常的算术转换(可能缩小一个参数而不是扩大另一个参数),除非它能证明最终结果在所有情况下都与标准规定的结果相同。(这里,“在所有情况下”实际上是指“在所有不表现出未定义行为的情况下”,但由于无符号算术是定义良好的,除除以/模0外,此细节在本例中不相关。)
如果表达式包含除法运算符,则溢出实际上很重要。考虑
(a + b) * c * (sizeof x) / (sizeof y)
其中a
,b
和c
都是相同的类型,比尺寸窄
与上面的逻辑一样,(a+b)*c在a
、b
和c
的常见类型中进行评估。然后将该结果提升为size\u t
,以便它可以乘以x
的大小。但肯定有可能(a+b)*c
在转换之前溢出,导致最终结果无效。坚持使用size\u t
操作数执行整个计算会更安全。这可以通过添加单个显式转换来实现:
((size_t)a + b) * c * (sizeof x) / (sizeof y)
当遇到参数大小不同的算术运算符时,编译器将应用,这基本上使两个操作数的类型相同
这在整个表达式中执行,一次一个运算符。根据C的语法将表达式分析为单独的操作;编译器不允许修改解析,除非它能证明结果没有差别(在这种情况下,修改或多或少是不相关的)
请考虑你的表达:
func((herp + derp) * durr * sizeof wut);
这在语法上等同于以下一系列操作,其中省略了类型和转换(目前):
前四个临时变量将自动键入每个运算符的结果类型(这是该运算符的常用算术转换生成的类型)
temp1=herp+derp代码>
herp
和derp
都是unsigned long
;不需要转换;结果类型为无符号长
temp2=temp1*durr代码>
temp1
和durr
都是unsigned long
;不需要转换;结果类型为无符号长
temp3=wut的大小代码>
sizeof
始终返回size\t
,因此这是结果的类型
temp4=temp2*temp3
temp2
是unsigned long
,temp3
是size\u t
,在示例平台上是unsigned long
。这需要将temp2
转换为unsigned long
,之后的结果类型为unsigned long
因此,我们可以在上面的示例代码中插入类型和转换:
unsigned long temp1 = herp + derp;
unsigned long temp2 = temp1 * durr;
unsigned long long temp3 = sizeof wut
unsigned long long temp4 = (unsigned long long)temp2 * temp3;
temp5 = (unsigned long)temp4;
func(temp5)
这里需要说明的关键是,结果将被转换为其他类型这一事实没有任何影响