我很好奇,如果我有两个指针
int *x = (int *)malloc(sizeof(int));
int *y;
我希望 y 指向 x 的地址,是
y = x;
一样
y = &*x;
?
您的问题有两个部分,值得注意的是它们并不都是正确的:
首先,你问:
是
y = x;
等同于
y = &*x;
由于取消引用 ( *
) 和地址 ( &
) 运算符具有相同的优先级,它们将从右到左绑定,所以
y = &*x;
是相同的:
y = &(*x);
是的,这将产生与现在相同的效果,y=x;
如果您有一个遵循法律条文的 C 兼容编译器,它不仅在有效方面是相同的,而且是相同的,这是由于第 6.5.3.2 节 P3 C规范的:
一元 & 运算符产生其操作数的地址。如果操作数的类型为“type”,则结果的类型为“pointer to type”。
如果操作数是一元 * 运算符的结果,则该运算符和 & 运算符都不会被计算,结果就好像两者都被省略了
所以编译器会同时看到*
and&
并完全忽略它们。
在你问题的后半部分,你说:
I want y to point to the address of x
大概您知道那不是您正在做的事情,但是您设置为y
指向相同的地址x
。x
当然有它自己的地址并且可以设置,但是你需要一个不同的变量int **y = &x;
,假设x
是一个有效的值被取消引用。
它们在功能上是等效的。这实际上是一个“浅拷贝”。
因此,以下分配实现了相同的最终结果:
y=x;
y=&(*x);
但是,第二个操作将花费更多时间来执行,因为您执行的不仅仅是直接赋值,而是执行间接寻址然后是地址操作。编译器可能只是将其优化到y=x
无论如何,具体取决于您的系统。
编辑:
正如下面的海报所指出的,如果你的编译器支持 C 标准,包括 C 标准的 6.5.3.2 P3,这肯定会被优化掉,可能在代码编译之前的预处理器级别。
它们要么在定义上完全相同,要么几乎相同,具体取决于您正在处理的 C 标准的版本。
在 ISO C99 和 C11 中,我们在 6.5.3.2 中有以下措辞(引用N1570 C11 草案):
一元运算
&
符产生其操作数的地址。如果操作数的类型为“ type ”,则结果的类型为“pointer to type ”。如果操作数是一元运算符的结果,则该运算*
符和该&
运算符都不会被计算并且结果就像两者都被省略了,除了对运算符的约束仍然适用并且结果不是左值。
所以给出:
int *x = /* whatever */;
int *y;
这两个是完全等价的,即使x
是一个空指针:
y = x;
y = &*x;
如果没有特殊情况规则,行为将是未定义的,因为*
运算符的行为仅在其操作数是有效的非空指针时才被定义。但由于*
从未评估过,它在这里没有任何行为,无论是定义的还是其他的。x
(与 不同,&*x
不是左值的事实在这里不相关。)
而在 C89/C90 中,尚未添加该特殊情况规则,因此如果是空(或其他无效)指针,&*x
则的行为未定义。x
大多数 C99 之前的编译器可能会优化掉*
and &
;请记住,未定义行为的本质是某些事物的行为可能与您预期的一样。
另一方面,阅读代码的任何人的行为都存在非常实际的差异。如果我看到y = x;
,我的行为是想“哦,这是一个普通的指针赋值”。如果我看到y = &*x;
,我的行为是想“你为什么要这样写?”,y = x;
如果我有能力这样做,就改变它。
是的,尽管第二个看起来像是混淆比赛的参赛作品。
是的,它们是相同的,但非常复杂。
您可以通过执行以下操作来测试:
y = &(*x);
printf("%p\n", (void*)x);
printf("%p\n", (void*)y);
据我所知,它们是完全等价的。如果某些编译器确实以不同的方式对待它们,我会感到惊讶。
由于 , 的存在&
,*x
根本不会被评估。因此,即使 x 为空,也不会导致崩溃/段故障。(您最好使用汇编进行验证。)
当我们谈论汇编时,不可能计算 *x (value) & 然后 &(*x) (pointer)。因此,编译器将简单地计算 *x 的地址,而不计算 *x 的值。
我们还可以检查更复杂的情况,例如&(a[10])
它只是a+10*sizeof(a[0])
在汇编中转换为。
另一个证明是offsetof
宏,通常定义为:
#define offsetof(st, m) ((size_t)(&((st *)0)->m))
在这里,它正在计算&(null_pointer->m)
,这不会导致崩溃。
这是一个方便的小功能,可能会有所帮助。不确定您是否需要所有“包含”。
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <typeinfo>
using namespace std;
int main() {
int *x = (int *)malloc(sizeof(int));
int *y = x;
int *z = &*x;
//y = x;
//z = &*x;
cout << "x has type: " << typeid(x).name() << '\n'
<< "y has type: " << typeid(y).name() << '\n'
<< "z has type: " << typeid(z).name() << '\n'
<< "values are " << x <<" "<< y << " " << z << '\n';
}
我从中得到的结果是:
x has type: Pi
y has type: Pi
z has type: Pi
values are 0x1a3a010 0x1a3a010 0x1a3a010
那么答案是,是的,使用 Ubuntu 14.10、g++ 的方法完全相同