3

想象一下你有这个功能:

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

现在您在呼叫站点这样称呼它:

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

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

现在,我知道这是因为 C++ 标准是这样说的,但是,技术上的原因是什么,它65不仅被提升为类型long,从而为我们节省了忘记L后缀以使其明确地变成 long 的愚蠢错误?

我在 C++ 标准中发现了这一点:

4.7 积分转换[conv.integral]

5 作为积分促销允许的转换不包括在积分转换集中。

我可以想,缩小转换不是隐式进行的,但这里的目标类型显然比源类型更宽。

编辑

这个问题是基于我之前看到的一个问题,当你没有指定L后缀时,它的行为很有趣。 示例,但也许它是 C 的东西,而不是 C++?!

4

5 回答 5

4

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

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

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

于 2013-03-18T16:29:53.907 回答
1

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

它本质上与表达式类似(1L + 1)- 因为整数1不是正确的类型,所以它被隐式转换为 along来执行计算,结果是 a long

如果您传入65L此函数调用,则无需进行类型转换,但没有实际区别 -65L无论哪种方式都可以使用。

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

如果表示被调用函数的表达式具有包含原型的类型,则参数将隐式转换为相应参数的类型,就像通过赋值一样,将每个参数的类型作为其声明的非限定版本类型。函数原型声明器中的省略号会导致参数类型转换在最后一个声明的参数之后停止。默认参数提升是在尾随参数上执行的。

于 2013-03-18T16:23:58.457 回答
1

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

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

现在,我知道这是因为 C++ 标准是这样说的,但是,这个 65 不只是被提升为类型的技术原因是什么,long从而为我们节省了忘记L后缀以使其long显式成为 a 的愚蠢错误?

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

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

于 2013-03-18T16:27:04.100 回答
0

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

编译器会在编译时自动“转换”您的常量表达式,因此传递给函数的有效值很长,但由于这个原因,在转换之前它被认为是一个 int。

于 2013-03-18T16:28:46.050 回答
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))。

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

于 2013-03-18T16:24:03.353 回答