C和C ++编译器为以下代码提供不同的消息,为什么?

时间:2012-02-20 16:01:36

标签: c++ c

我被要求在面试中提供以下代码的输出。

int a[] = {1,2,3,4,5};
int *p = &a + 1;
printf("%d, %d", *(a+1), *(p - 1));

我说我无法确定第二个结果,所以我没能通过采访。

当我回到家中并尝试编译代码时,g ++会报告错误,但gcc只会发出警告。打印结果为“2,5”。

任何人都知道为什么C和C ++编译器在这方面表现不同?

4 个答案:

答案 0 :(得分:10)

a是一个整数数组,在需要时会转换为指向第一个元素的指针。 a+1调用该转换,并给出指向第二个元素的指针。

&a是一个指向数组本身的指针,而不是它的第一个元素,所以&a + 1指向数组的末尾(到第二个数组的位置,如果是是一个二维数组。)

然后代码将该指针(类型为int (*)[5])转换为指向整数(类型int*)的指针。没有明确的reinterpret_cast,C ++不允许这样的转换,而C在它允许的指针转换中更宽松。

最后(假设pp2应该是同一个事物),p - 1指向a的最后一个元素。

答案 1 :(得分:5)

嗯,a是5个整数的数组,因此&a是指向5个整数数组的指针。在C ++中,如果没有强制转换,则无法在int*中分配该地址。 gcc(用C语言)只给出警告,但我认为这不是有效的C。

代码:

&a+1a之后的下一个数组,意思是a中第6个元素的地址,因此p-1是{{1}的第5个元素的地址1}}。

(我不确定a是否合法。它是数组之后的元素的地址,通常是合法的,但由于&a+1不是数组,它可能是非法的。)

答案 2 :(得分:2)

int a[] = {1,2,3,4,5};
int *p = &a + 1;

这是无效的C代码。

表达式&a + 1的类型为int (*)[5]。您无法将int (*)[5]类型的表达式分配给int *

除了通用对象指针类型void *之外,对象指针之间没有隐式转换。需要使用强制转换来初始化p &a + 1值。

C声明此声明无效?

int *p = &a + 1;

在赋值运算符的约束中:

  

(C99,6.5.16.1p1)“两个操作数都是兼容类型的限定或非限定版本的指针,左边指向的类型具有右边指向的类型的所有限定符”

int和数组类型不兼容类型(有关类型兼容性的更多信息,请参阅6.2.7p1。)

同样,它是初始化而不是赋值,但适用相同的约束:

  

(C99,6.7.8p11)“标量的初始值设定项应该是单个表达式,可选择用大括号括起来。对象的初始值是表达式的初始值(转换后);相同的类型约束和转换为对于简单赋值应用,将标量的类型作为其声明类型的非限定版本。“

答案 3 :(得分:0)

C ++编译器发出错误,因为&a计算结果为int(*)[5],这是指向5个整数的指针,并且您尝试将其分配给int*

如果您确实修改了类型,此代码将打印数组中的第二项,后跟数组的地址。

我的猜测是C将数组衰减为指针,导致&a评估为int**,并允许将其分配给int*。但是,我没有做太多的C,所以其他人可能会更清楚。