类型升级/转换

类型升级/转换

问题描述:

sizeof运算符的结果似乎是size_t类型,它在Windows 64位上定义为无符号long long。类型升级/转换

考虑下面的一段(伪)代码:

int func(unsigned long arg) 
{ 
    /* ... */ 
} 

/* ... */ 

unsigned long herp = 3, 
       derp = 5, 
       durr = 7; 

wchar_t wut; 

func(/* ... */); 

当func被称为如下什么实际发生在这里型推广/换算的?

func((herp + derp) * durr * sizeof wut); // 1st example 

是HERP,DERP和杜尔的值第一晋升为unsigned long long然后再对结果进行评估后,结果被转换回为unsigned long?

而是,如下所示调用func时,是唯一发生类型转换为无符号long的转换?

func((herp + derp) * durr * (unsigned long)sizeof wut); // 2nd example 

考虑到类型转换/提升,什么是最适合/正确的方式来调用func?

+0

'(herp + derp)'对'size_t'一无所知,所以不被提升。但算术计算的值在计算之前会提升为本地整数类型(如果更短)。 –

当遇到算术运算符的参数大小不同时,编译器应用"Usual Arithmetic Conversions",它们基本上使两个操作数都是相同的类型。

这是贯穿一个表达式,一次一个操作符执行的。根据C的语法将表达式分解为单独的操作;编译器不允许修改解析,除非它能证明结果没有区别(在这种情况下,修改或多或少是不相关的)。

因此,考虑你的表达:

func((herp + derp) * durr * sizeof wut); 

这句法等同于下面的一系列操作中,哪些类型和转换都省略(现在):

temp1 = herp + derp; 
temp2 = temp1 * durr; 
temp3 = sizeof wut 
temp4 = temp2 * temp3; 
temp5 = (unsigned long) temp4; 
func(temp5) 

前四临时对象会自动键入每个运算符的结果类型(这是该运算符的常用算术转换生成的类型)。

  1. temp1 = herp + derp;

    herpderp均为unsigned long;没有转换是必要的;结果类型是unsigned long

  2. temp2 = temp1 * durr;

    temp1durr均为unsigned long;没有转换是必要的;结果类型是unsigned long

  3. temp3 = sizeof wut;

    sizeof总是返回size_t,所以这是结果的类型。

  4. temp4 = temp2 * temp3

    temp2unsigned longtemp3size_t,其示例平台上是unsigned long long。这需要将temp2转换为unsigned long long,之后结果类型为unsigned long 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) 

其中abc是情况下,所有相同类型的,这是窄于size_t

与上述逻辑一样,(a + b) * c在普通类型a,bc中评估。然后将结果提升为size_t,以便它可以乘以x的大小。但在转换之前(a + b) * c肯定会溢出,导致最终结果无效。坚持使用size_t操作数来执行整个计算会更安全。这可以通过添加一个明确的转换来完成:

((size_t)a + b) * c * (sizeof x)/(sizeof y) 
+0

感谢您花时间回答我的问题。您的解释非常感谢,并帮助我更好地理解算术转换。 – treintje