4

我很好奇,如果我有两个指针

int *x = (int *)malloc(sizeof(int));
int *y;

我希望 y 指向 x 的地址,是

y = x;

一样

y = &*x;

?

4

7 回答 7

9

您的问题有两个部分,值得注意的是它们并不都是正确的:

首先,你问:


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指向相同的地址xx当然有它自己的地址并且可以设置,但是你需要一个不同的变量int **y = &x;,假设x是一个有效的值被取消引用。

于 2013-06-03T15:57:08.940 回答
4

它们在功能上是等效的。这实际上是一个“浅拷贝”。

因此,以下分配实现了相同的最终结果:

y=x;

y=&(*x);

但是,第二个操作将花费更多时间来执行,因为您执行的不仅仅是直接赋值,而是执行间接寻址然后是地址操作。编译器可能只是将其优化到y=x无论如何,具体取决于您的系统。

编辑:


正如下面的海报所指出的,如果你的编译器支持 C 标准,包括 C 标准的 6.5.3.2 P3,这肯定会被优化掉,可能在代码编译之前的预处理器级别。

于 2013-06-03T15:43:55.033 回答
3

它们要么在定义上完全相同,要么几乎相同,具体取决于您正在处理的 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;如果我有能力这样做,就改变它。

于 2013-06-03T18:24:50.090 回答
2

是的,尽管第二个看起来像是混淆比赛的参赛作品。

于 2013-06-03T15:44:45.903 回答
2

是的,它们是相同的,但非常复杂。

您可以通过执行以下操作来测试:

y = &(*x);
printf("%p\n", (void*)x);
printf("%p\n", (void*)y);
于 2013-06-03T15:45:12.020 回答
1

据我所知,它们是完全等价的。如果某些编译器确实以不同的方式对待它们,我会感到惊讶。

由于 , 的存在&*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),这不会导致崩溃。

于 2013-06-03T16:01:54.377 回答
-1

这是一个方便的小功能,可能会有所帮助。不确定您是否需要所有“包含”。

#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++ 的方法完全相同

于 2014-12-20T20:26:24.887 回答