【发布时间】:2012-02-23 13:48:25
【问题描述】:
假设我有 2 个指针:
int *a = something;
int *b = something;
如果我想比较它们,看看它们是否指向同一个地方,(a == b) 是否有效?
【问题讨论】:
-
IIRC 比较指针是未定义的,除非它们指向同一个数组中的元素
-
@sehe 嘿,您在下面的回答取消了这条旧评论。
假设我有 2 个指针:
int *a = something;
int *b = something;
如果我想比较它们,看看它们是否指向同一个地方,(a == b) 是否有效?
【问题讨论】:
关于事实这里是规范中的相关文本
可以将指向相同类型对象的指针与“直观”的预期结果进行比较:
来自 C++11 标准的 § 5.10:
相同类型的指针 (指针转换后)可以比较是否相等。相同类型的两个指针比较相等 if 并且只有当它们都为空,都指向同一个函数,或者都代表同一个地址时(3.9.2)。
(省略了比较成员指针和/或空指针常量的详细信息 - 它们继续沿着“Do What I mean”的同一行:)
- [...] 如果两个操作数都为空,则它们比较相等。否则,如果只有一个为空,则它们比较不相等。[...]
最“显着”的警告与虚拟有关,这似乎也是合乎逻辑的事情:
- [...] 如果其中一个是指向虚成员函数的指针,则结果未指定。否则他们 当且仅当它们引用同一个最衍生对象的同一个成员时才比较相等(1.8) 或相同的子对象,如果它们被关联类类型的假设对象取消引用。 [...]
来自 C++11 标准的 § 5.9:
可以比较指向相同类型的对象或函数的指针(指针转换后), 结果定义如下:
- 如果两个相同类型的指针 p 和 q 指向同一个对象或 函数,或者两者都指向同一个数组的末尾,或者两者都是 null,然后
p<=q和p>=q都产生true,p<q和p>q都产生false。- 如果两个相同类型的指针 p 和 q 指向不同的对象 不是同一对象的成员或同一数组的元素或不同 函数,或者如果其中只有一个为空,则
p<q,p>q,p<=q,和p>=q未指定。- 如果两个指针指向同一个对象的非静态数据成员,或者指向 此类成员的子对象或数组元素,递归地,指向 稍后声明的成员比较更大,前提是这两个成员具有相同的 访问控制(第 11 条),并提供他们的类不是联合。
- 如果两个指针指向同一个对象的非静态数据成员 不同的访问控制(第 11 条)结果未指定。
- 如果两个指针指向同一个联合对象的非静态数据成员, 它们比较相等(如有必要,在转换为
void*之后)。如果两个指针 指向同一数组的元素或数组末尾之外的元素, 指向具有较高下标的对象的指针比较高。- 未指定其他指针比较。
所以,如果你有:
int arr[3];
int *a = arr;
int *b = a + 1;
assert(a != b); // OK! well defined
也可以:
struct X { int x,y; } s;
int *a = &s.x;
int *b = &s.y;
assert(b > a); // OK! well defined
但这取决于您问题中的 something:
int g;
int main()
{
int h;
int i;
int *a = &g;
int *b = &h; // can't compare a <=> b
int *c = &i; // can't compare b <=> c, or a <=> c etc.
// but a==b, b!=c, a!=c etc. are supported just fine
}
§ 20.8.5/8:“对于模板 greater、less、greater_equal 和 less_equal,任何指针类型的特化都会产生一个总顺序,即使内置运算符 <、>、<=、>= 没有。"
所以,您可以全局订购任何奇怪的void*,只要您使用std::less<> 和朋友,而不是单纯的operator<。
【讨论】:
int *a = arr; 行是否会受益于包含对 stackoverflow.com/questions/8412694/address-of-array 的引用?我不确定它是否与所提出的问题足够相关......
<functional> 中定义的函数对象模板有更严格的规范。已添加。
是的,这就是raw pointer相等的定义:它们都指向同一个位置(或者是pointer aliases);通常在process 的virtual address space 中运行用C++ 编码并由一些operating system 管理的应用程序(但C++ 也可用于使用具有Harward architecture 的微控制器对嵌入式设备进行编程:在此类微控制器上一些指针强制转换是被禁止的并且没有任何意义——因为只读数据可以位于代码 ROM 中)
对于 C++,请阅读 a good C++ programming book,查看 this C++ reference 网站,阅读 C++ 编译器的文档(可能是 GCC 或 Clang)并考虑使用 smart pointers 进行编码。也可以阅读一些 C++ 标准草案,例如 n4713 或从您的 ISO 代表处购买官方标准。
garbage collection 的概念和术语在管理通过动态分配获得的指针和内存区域时也很相关(例如::operator new),所以不妨阅读GC handbook。
有关 Linux 机器上的指针,另请参阅 this。
【讨论】:
指针上的== 运算符将比较它们的数字地址,从而确定它们是否指向同一个对象。
【讨论】:
总结一下。如果我们想查看两个指针是否指向同一个内存位置,我们可以这样做。此外,如果我们想比较两个指针指向的内存内容,我们也可以这样做,只需记住先取消引用它们。
如果我们有
int *a = something;
int *b = something;
我们可以使用两个相同类型的指针:
比较内存地址:
a==b
并比较内容:
*a==*b
【讨论】:
比较指针不可移植, 例如在 DOS 中不同的指针值点 到同一个位置,比较 的指针返回 false。
/*--{++:main.c}--------------------------------------------------*/
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int val_a = 123;
int * ptr_0 = &val_a;
int * ptr_1 = MK_FP(FP_SEG(&val_a) + 1, FP_OFF(&val_a) - 16);
printf(" val_a = %d -> @%p\n", val_a, (void *)(&val_a));
printf("*ptr_0 = %d -> @%p\n", *ptr_0, (void *)ptr_0);
printf("*ptr_1 = %d -> @%p\n", *ptr_1, (void *)ptr_1);
/* Check what returns the pointers comparison: */
printf("&val_a == ptr_0 ====> %d\n", &val_a == ptr_0);
printf("&val_a == ptr_1 ====> %d\n", &val_a == ptr_1);
printf(" ptr_0 == ptr_1 ====> %d\n", ptr_0 == ptr_1);
printf("val_a = %d\n", val_a);
printf(">> *ptr_0 += 100;\n");
*ptr_0 += 100;
printf("val_a = %d\n", val_a);
printf(">> *ptr_1 += 500;\n");
*ptr_1 += 500;
printf("val_a = %d\n", val_a);
return EXIT_SUCCESS;
}
/*--{--:main.c}--------------------------------------------------*/
在Borland C 5.0下编译,结果如下:
/*--{++:result}--------------------------------------------------*/
val_a = 123 -> @167A:0FFE
*ptr_0 = 123 -> @167A:0FFE
*ptr_1 = 123 -> @167B:0FEE
&val_a == ptr_0 ====> 1
&val_a == ptr_1 ====> 0
ptr_0 == ptr_1 ====> 0
val_a = 123
>> *ptr_0 += 100;
val_a = 223
>> *ptr_1 += 500;
val_a = 723
/*--{--:result}--------------------------------------------------*/
【讨论】:
这取决于值的类型,以及碰巧定义运算符的方式。例如,字符串比较是按值,而不是按地址。但是 char * 通常是按地址(我认为)。
粗心大意的陷阱。没有保证的指针比较运算符,但是
(void *)a == (void *)b
可能相当安全。
【讨论】:
检查指针别名的简单代码:
int main () {
int a = 10, b = 20;
int *p1, *p2, *p3, *p4;
p1 = &a;
p2 = &a;
if(p1 == p2){
std::cout<<"p1 and p2 alias each other"<<std::endl;
}
else{
std::cout<<"p1 and p2 do not alias each other"<<std::endl;
}
//------------------------
p3 = &a;
p4 = &b;
if(p3 == p4){
std::cout<<"p3 and p4 alias each other"<<std::endl;
}
else{
std::cout<<"p3 and p4 do not alias each other"<<std::endl;
}
return 0;
}
输出:
p1 and p2 alias each other
p3 and p4 do not alias each other
【讨论】: