扩大整体类型?

时间:2013-03-18 16:11:23

标签: c++ integer-promotion

想象一下你有这个功能:

void foo(long l) { /* do something with l */}

现在你在呼叫网站上这样称呼它:

foo(65); // here 65 is of type int

为什么(技术上)当你在函数的声明中指定你期望long而你只传递一个没有L后缀的数字时,它是否被视为{{ 1}}?

现在,我知道这是因为C ++标准这样说,但是,这个int不仅仅被提升为类型65的技术原因是什么,所以拯救我们愚蠢忘记long后缀使其显式变长的错误?

我在C ++标准中找到了这个:

4.7积分转换[conv.integral]

  

5作为整体促销所允许的转化不包括在整数转化中。

我无法隐含地进行缩小转换,但是这里目标类型明显比源类型宽。

修改

这个问题基于我之前看到的a question,当你没有指定L后缀时,这个问题很有趣。 Example,但也许它是C语言,而不是C ++?!!

5 个答案:

答案 0 :(得分:4)

在C ++中,对象和值具有一种类型,与您使用它们的方式无关。然后当你使用它们时,如果你需要一个不同的类型,它将被适当地转换。

链接问题中的问题是varargs不是类型安全的。它假定您传入正确的类型,并解释它们是什么。在处理调用者时,编译器不知道被调用者将如何解码每个参数,因此它不可能为您转换它们。实际上,varargs与转换为void*并转换回不同类型一样是类型安全的,如果你做得对,你会得到你推进的内容,如果你弄错了,你就会变成垃圾。

另请注意,在这种特殊情况下,内联编译器足够的信息,但这只是一般家庭的一个小例子,如果有错误。考虑printf函数族,取决于第一个参数的内容,每个参数作为不同的类型处理。试图在语言层面修复这种情况会导致不一致,在某些情况下,编译器做正确的事情或错误的事情,并且用户不清楚何时可以预期哪些事情,包括它可以做到的事实今天是正确的事情,如果在重构过程中函数定义被移动并且不可用于内联,或者如果函数的逻辑发生变化并且参数根据某个先前的参数被处理为一种或另一种类型,则明天是错误的。

答案 1 :(得分:1)

此实例中的函数确实收到long,而不是int。如果可能的话,编译器会自动将任何参数转换为所需的参数类型,而不会丢失任何信息(如此处所示)。这是函数原型很重要的主要原因之一。

它与(1L + 1)这样的表达式基本相同 - 因为整数1不是正确的类型,它隐式转换为long来执行计算,结果是long

如果您在此函数调用中传递65L,则不需要进行类型转换,但没有实际区别 - 65L以任何一种方式使用。

虽然不是C ++,但这是C99标准的相关部分,它也解释了var args note:

  

如果表示被调用函数的表达式具有类型   确实包含一个原型,参数被隐式转换为   如果通过赋值,对相应参数的类型,采取   每个参数的类型是它的不合格版本   声明的类型。函数原型中的省略号表示法   声明器导致参数类型转换在最后一个之后停止   声明参数。执行默认参数促销   尾随论据。

答案 2 :(得分:1)

  

为什么(技术上)当你在函数的声明中指定你期望很长并且只传递一个没有L后缀的数字时,它是否被视为int

因为文字的类型仅由文字的形式指定,而不是使用它的上下文。对于整数,即int,除非该值对于该类型而言太大,或者后缀用于指定其他类型。

  

现在,我知道这是因为C ++标准这样说,但是,这个65不仅仅被提升为long类型的技术原因是什么,因此拯救我们忘记{的愚蠢错误{1}}后缀是否明确表示L

无论是否明确指定该类型,该值都应提升为long,因为声明该函数采用类型为long的参数。如果没有发生这种情况,或许您可以举例说明失败的代码,并描述它是如何失败的?

更新:您给出的示例将文字传递给采用无类型省略号(long)参数的函数,而不是类型化的...参数。在这种情况下,函数调用者不知道期望什么类型,并且仅应用默认参数提升。具体而言,类型long的值在通过省略号参数时仍为int

答案 3 :(得分:0)

C标准规定:

  

“整数常量的类型是相应列表中可以表示其值的第一个。”

在C89中,此列表为:

  

int, long int, unsigned long int

C99将该列表扩展为包括:

  

long long int, unsigned long long int

因此,当编译代码时,文字65适合int类型,因此它的类型相应为int。然后在调用函数时将int提升为long。

例如,如果sizeof(int)== 2,并且您的文字类似于64000,则值的类型将为long(假设sizeof(long)> sizeof(int))。

后缀用于覆盖默认行为并强制指定的文字值为特定类型。当整数提升很昂贵时(例如,作为紧密循环中的等式的一部分),这可能特别有用。

答案 4 :(得分:0)

我们必须对类型有一个标准含义,因为对于较低级别的应用程序,类型真的很重要,特别是对于整数类型。低级操作符(例如bitshift,add,ect)依赖于输入的类型来确定溢出位置。 ((65 <2)整数是260(0x104),但是单个char是4!(0x004))。有时候你想要这种行为,有时你却不想。作为程序员,您只需要能够始终知道编译器将要执行的操作。因此,设计决策是为了使人明确地声明其常量的整数类型,将“未修饰”作为最常用的类型,整数。

编译器会在编译时自动“强制转换”常量表达式,这样传递给函数的有效值很长,但是直到转换它才被认为是int。