ean*_*mos 3 c gcc pointers clang language-lawyer
#include <stdio.h>
int main(void)
{
int a, b;
int *p = &a;
#ifdef __clang__
int *q = &b + 1;
#elif __GNUC__
int *q = &b - 1;
#endif
printf("%p %p %d\n", (void *)p, (void *)q, p == q);
}
Run Code Online (Sandbox Code Playgroud)
C11 § 6.5.9 \ 6 说
两个指针比较相等当且仅当它们都是空指针,都是指向同一个对象的指针(包括指向一个对象的指针和它开头的子对象)或函数,都是指向同一数组最后一个元素之后的指针对象,或者一个是指向一个数组对象末尾的指针,另一个是指向另一个数组对象开头的指针,该对象恰好紧跟地址空间中的第一个数组对象。
我已经通过四种不同的方式对其进行了测试:
-01选项;-01选项;结果如下:
$ ./prog_clang
0x7ffebf0a65d4 0x7ffebf0a65d4 1
$ ./prog_clang_01
0x7ffd9931b9bc 0x7ffd9931b9bc 1
$ ./prog_gcc
0x7ffea055a980 0x7ffea055a980 1
$ ./prog_gcc_01
0x7fffd5fa5490 0x7fffd5fa5490 0
Run Code Online (Sandbox Code Playgroud)
在这种情况下,正确的行为是什么?
在这种情况下,正确的行为是什么?
空无一人。比较指向或超过两个完全不相关对象的末尾的指针是未定义的行为。
根据C11 标准的脚注 109(粗体是我的):
两个对象在内存中可能是相邻的,因为它们是较大数组的相邻元素或结构的相邻成员,它们之间没有填充,或者因为实现选择这样放置它们,即使它们不相关。如果先前的无效指针操作(例如数组边界外的访问)产生未定义行为,则后续比较也会产生未定义行为。
两个指针比较相等当且仅当两者都是空指针时,
他们不是空的
两者都是指向同一对象的指针(包括指向对象的指针和位于其开头的子对象)或函数
它们不指向同一个对象,也不是子对象,也不是函数
两者都是指向同一数组对象最后一个元素的指针,
它们不是指向数组元素的指针。
或者一个是指向一个数组对象末尾的指针,另一个是指向另一个数组对象开始的指针,该对象恰好紧跟在地址空间中的第一个数组对象之后。
它们不是指向数组元素的指针。
因此,根据标准,您的指针不符合相等比较的要求,并且不应该进行相等比较。
现在,在您的测试中,在前三种情况下,指针实际上比较相等。可以说编译器没有严格遵守标准,因为标准说“当且仅当”,但正如您所见,不带 -O1 的 clang 和 gcc 表现得好像标准说“如果”而没有“和”只有当”部分。编译器只是不尝试采取额外措施来确保“且仅当”部分得到尊重,因此他们允许指针比较相等,这纯粹是巧合,尽管事实上根据标准,它们不应该。
由于这纯粹是巧合,在最后一种情况下,由于与编译器的优化实现有关的许多未知原因,这种巧合不再成立。编译器可能已经决定颠倒堆栈中变量的顺序,或者让它们彼此远离,或者谁知道是什么。
| 归档时间: |
|
| 查看次数: |
227 次 |
| 最近记录: |