如果变量 a 是 char 数组是 char* p = &a 在 C++ 中定义的行为

Posted

技术标签:

【中文标题】如果变量 a 是 char 数组是 char* p = &a 在 C++ 中定义的行为【英文标题】:If variable a is a char array is char* p = &a defined behaviour in C++ 【发布时间】:2018-03-06 23:46:39 【问题描述】:

我一直认为:

char a[10];
char* p = &a;

是错误的,应该是以下之一:

char a[10];
char* p = a; // OR
char* p = &a[0];

我希望我能在这里找到线程所以我正在阅读说 p = &a;是有效的,而且是关于 C 语言,而不是 C++。

显然我一直在想:

char* p = new char[10];
char* p1 = &p; // Is wrong

但是当一个数组被创建为堆栈空间中的一个本地数组时,我的直觉认为a&a&a[0] 都是相同的值/地址似乎是合理的。我不得不说,我一直在关注 C++ 并没有看到它以这种方式完成,这就是为什么当我开始研究 C 时,我很快将其称为错误,但我确定它不在 C 中(很好验证对此也将不胜感激)。我只是想知道在 C++ 中是否也是这种情况,因为据我记得在 C++ 中通常是用其他两种方式之一完成的,而这种方式(如果我的想象力不是在玩诡计)似乎在 C 中完成。

编辑:这是一个非常愚蠢的问题。我的困惑来自于我的 Visual Studio 编译器用 C 编译它,而不是用 C++ 编译它,所以我认为这方面的语言有所不同。我不会删除这个问题,因为它已经有了答案。

【问题讨论】:

相同的地址,不同的类型。你的编译器应该给你一个类型不匹配的错误,因为 p 是一个指向 char 的指针,而 &a 是一个指向 10 个字符的数组的指针。 @immibis 哦,我明白了。我已经为 C 和 C++ 设置了 Visual Studio,我刚刚尝试过,这似乎是这两种语言之间的另一个差异。 考虑以下几点:struct foo int x; int y; ; struct foo obj; int *ptr = &obj; 这两种语言的区别是什么意思?两者都是一样的。 @melpomene 在带有 GCC 的在线编译器上,它确实说类型不匹配。在我的 Visual Studio 上,严格使用 C 编译并禁用语言扩展,它编译得很好。事实上,有人在这里发布了 C 代码作为一个问题,他的算法运行良好,没有人叫他出来。奇怪的。我希望我能找到那个问题.. 【参考方案1】:
char a[10];
char* p = &a;

在 C 中确实是错误的。

特别是(所有引用均参考 ISO 9899:1999 (C99),所有重点都是我的):

6.7.8(初始化)/11 说:

标量的初始值设定项应该是一个表达式,可选地用大括号括起来。这 对象的初始值是表达式的初始值(转换后); 同一类型 应用简单赋值的约束和转换,采用标量的类型 成为其声明类型的非限定版本。

6.5.16.1(简单赋值):

约束

    应满足以下条件之一: 左边的操作数有合格或不合格的算术类型,右边有 算术类型; 左操作数具有结构或联合类型的合格或不合格版本 与权利类型兼容; 两个操作数都是指向兼容类型的合格或不合格版本的指针, 并且 left 指向的类型具有指向的类型的所有限定符 对; 一个操作数是指向对象或不完整类型的指针,另一个是指向对象的指针 void 的合格或不合格版本,左边指向的类型全部 右边指向的类型的限定符; 左操作数是指针,右操作数是空指针常量;或 左侧操作数的类型为_Bool,右侧是指针。

只有粗体部分适用;我们没有使用任何算术或结构/联合类型,没有void_Bool,也没有空指针常量。

有问题的类型是左侧的char *(指向char 的指针)和右侧的char (*)[10](指向char 的数组[10] 的指针)。指针类型的兼容性定义如下:

6.7.5.1(指针声明符)/2:

为了使两种指针类型兼容,两者都应具有相同的限定,并且 两者都应 是指向兼容类型的指针

指向的类型分别是charchar [10]

但现在我们陷入了困境。有6.2.7(兼容型和复合型)/1:

如果它们的类型相同,则两种类型具有兼容类型。附加规则 类型说明符的 6.7.2 中描述了确定两种类型是否兼容, 在 6.7.3 中用于类型限定符,在 6.7.5 中用于声明符。

charchar [10] 显然不一样。 6.7.5 中兼容类型的所有声明符规则都说“要兼容的两个指针类型 ...”、“要兼容的两个数组类型 ... ", "要兼容两种函数类型...",但是没有办法让非数组类型兼容数组类型。

因此类型不兼容,char *p = &a 违反了 6.5.16.1 中的约束。

5.1.1.3(诊断):

符合要求的实现应产生至少一个诊断消息(在 一个实现定义的方式)如果一个预处理翻译单元或翻译单元 包含违反任何语法规则或约束,即使该行为也是显式的 指定为未定义或实现定义。

这意味着需要警告或错误消息。如果你的编译器没有产生一个,它就不是一个真正的 C 编译器。

【讨论】:

我总是对你们中的一些人能以多快的速度从标准中获得正确的段落感到惊讶。每次尝试,我都会迷失在文档中。 @Pablo 哈。实际上,在编写该答案的过程中,我不得不处理真正的 Windows 蓝屏 + 内存转储(然后重新启动)。 哪条评论,你的意思是答案?我不明白你想告诉我什么。 @Pablo 我说我觉得你认为它很快很有趣,因为对我来说,等待内存被转储、等待 Windows 重新启动、等待浏览器再次出现,等等。:-) 哈哈,我明白了。即使在那个时候你才写答案,我可能无论如何也找不到正确的地方。

以上是关于如果变量 a 是 char 数组是 char* p = &a 在 C++ 中定义的行为的主要内容,如果未能解决你的问题,请参考以下文章

数组名相当于一个指针,哪数组指针char *p[],不就变成一个二级指针?

数组与指针

关于char 指针变量char *=p;这个语句的输出问题

如何从string类型的变量 返回一个char* 类型

字符指针和字符数组

const char *p; char const *p; char * const p的区别