【问题标题】:C and C++ compiler give different messages for the following code, why?C 和 C++ 编译器对以下代码给出不同的消息,为什么?
【发布时间】:2012-02-20 16:01:36
【问题描述】:

我被要求在一次采访中给出以下代码的输出。

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

我说我不能确定第二个的结果,所以面试失败了。

当我回到家,尝试编译代码时,g++会报错,而gcc只会给出警告。打印的结果是'2,5'。

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

【问题讨论】:

  • 报告的错误和警告是什么?
  • 这是你的错字吗?因为 p 是未定义的。你的意思是说 p2 - 1?
  • C 和 C++ 是不同的语言。
  • 这个问题确实有道理。不过里面可能有几个错别字。
  • 哦,我以为问题是“为什么 C 和 C++ 编译器在这方面表现不同?”

标签: c++ c


【解决方案1】:

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

&a 是指向数组本身的指针,而不是指向它的第一个元素,因此&a + 1 指向数组末尾之外(如果它是 2-,则指向第二个数组所在的位置)维数组)。

然后代码将该指针(int (*)[5] 类型)转换为指向整数的指针(int* 类型)。 C++ 不允许在没有显式 reinterpret_cast 的情况下进行此类转换,而 C 在允许的指针转换方面更为宽松。

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

【讨论】:

  • 然而,C 编译器应该发出警告。
  • @PerJohansson 问题,你只需要调整编译器警告级别
【解决方案2】:

好吧,a 是 5 个整数数组,所以 &a 是一个指向 5 个整数数组的指针。在 C++ 中,您不能在不强制转换的情况下在 int* 中分配该地址。 gcc(用 C 语言)只给出警告,但我认为那不是有效的 C。

代码:

&a+1a之后的下一个数组,意思是a中第6个元素的地址,所以p-1就是a中第5个元素的地址。

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

【讨论】:

  • 我认为&a+1 是合法的。出于指针算术的目的,对象被视为大小为 1 的数组。数组a 除了是数组之外,当然也是一个对象,所以&a+1 是一个合法的指针。其中。也就是说,int[1][5] 类型的数组的最后一个。因此,正如您所说,它与过去的指针a+5 引用相同的地址,但类型不同。你也可以int i = 0; &i+1;
【解决方案3】:
int a[] = {1,2,3,4,5};
int *p = &a + 1;

这是无效的 C 代码。

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

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

C 在哪里说这个声明无效?

int *p = &a + 1;

在赋值运算符的约束中:

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

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

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

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

【讨论】:

  • 需要强制转换...强制编译器保持安静,即使操作无效:)
  • @WilliBurkhardt 在 C89、C99 和 C11 中无效。长话短说,这是一个初始化,但您必须查看赋值运算符的约束。
  • @WilliBurkhardt 这不是有效的代码,但一些糟糕的隐式转换使这成为可能
  • @WilliBurkhardt 转换后 认为算术类型,因为据我所知,对象指针类型没有隐式或自动转换。 6.3.2.3p5、p6 和 p7 中的转换不是隐式的,需要强制转换。
  • @WilliBurkhardt “否则”部分适用,这只是说&a 是指向a 数组的指针。在关于无效代码的讨论中,我认为这一段与此无关。
【解决方案4】:

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

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

我的猜测是 C 将数组衰减为指针,导致 &a 评估为 int**,并允许将其分配给 int*。不过,我不会做太多C,所以其他人可能知道得更好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 2010-10-26
    • 1970-01-01
    • 2015-10-30
    相关资源
    最近更新 更多