设置指针的这两种方法是否相同?

时间:2013-06-03 15:41:25

标签: c pointers

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

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

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

y = x;

相同
y = &*x;

7 个答案:

答案 0 :(得分:8)

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

首先,你问:

  

是   
y = x;   
同样的   
y =& * x;

由于取消引用(*)和地址(&)运算符具有相同的precedence,因此它们将从右向左绑定,因此

y = &*x;

与:

相同
y = &(*x);

是的,这将产生与y=x;相同的效果现在,如果你有一个遵循法律规定的C兼容编译器,它将不仅有效,它相同,这是由于C规范的第6.5.3.2节P3:

  

一元&运算符产生其操作数的地址。如果操作数的类型为''type'',   结果有''指向类型''的类型。

     

如果操作数是一元*运算符的结果,   无论是运营商还是&运算符被评估,结果就像两者都是   省略

因此,编译器将同时看到*&,并完全省略它们。


在你问题的后半部分,你说:

I want y to point to the address of x

据推测,您知道这不是您正在做的事情,但您要将y设置为指向相同的地址而不是xx当然有自己的地址,可以设置,但是你需要一个不同的变量int **y = &x;,假设x是一个有效的值,需要解除引用。

答案 1 :(得分:4)

它们功能等效。这实际上是一个“浅层副本”。

因此,以下作业达到了相同的最终结果:

y=x;

y=&(*x);

但是,第二个操作需要更多时间才能执行,因为您不是直接分配,而是执行间接,然后执行地址操作。无论如何,编译器可能会将其优化为y=x,具体取决于您的系统。

编辑:


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

答案 2 :(得分:3)

根据定义,它们要么完全相同,要么几乎相同,具体取决于您正在处理的C标准版本。

在ISO C99和C11中,我们在6.5.3.2中有以下措辞(引用N1570 C11草案):

  

一元&运算符生成其操作数的地址。如果   操作数的类型为“ type ”,结果的类型为“指向 type ”的指针。如果   操作数是一元*运算符的结果,也不是   运算符和&运算符都被计算,结果就像是   除了对运算符的约束之外,两者都被省略了   申请,结果不是左值。

所以给出:

int *x = /* whatever */;
int *y;

这两个完全等效,即使x是空指针

y = x;
y = &*x;

如果没有特殊情况规则,行为将是未定义的,因为*运算符的行为仅在其操作数是有效的非空指针时才被定义。但由于永远不会评估*,因此此处没有行为,定义或其他行为。 (事实上​​,与x不同,&*x不是左值,这与此无关。)

在C89 / C90中,尚未添加该特例规则,因此如果&*x为空(或其他方式),则x 的行为未定义无效)指针。大多数C99之前的编译器可能会优化掉*&;请记住,可以行为的行为与未预期行为的性质正如您预期的那样。

另一方面,阅读代码的人的行为存在非常真实的差异。如果我看到y = x;,我的行为是想“哦,这是一个普通的指针赋值。”如果我看到y = &*x;,我的行为就是思考“为什么你这样写呢?”如果我能够这样做的话,将其改为y = x;

答案 3 :(得分:2)

是的,虽然第二个看起来像混淆比赛的条目。

答案 4 :(得分:2)

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

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

y = &(*x);
printf("%p\n", (void*)x);
printf("%p\n", (void*)y);

答案 5 :(得分:1)

据我所知,它们完全相同。如果某些编译器确实以不同方式处理它们,我会感到惊讶。

由于&的存在,*x根本不会被评估。因此,即使x为null,也不会导致崩溃/ seg-fault。 (您可以使用程序集进行最佳验证。)

当我们谈论组装时,不可能计算* x(值)&然后&(* x)(指针)。 因此,编译器将简单地计算* x的地址,而不计算* x的值。

我们还可以检查更复杂的案例,例如&(a[10])它只是转换为汇编中的a+10*sizeof(a[0])

另一个证据是offsetof宏,通常定义为:

#define offsetof(st, m) ((size_t)(&((st *)0)->m))

这里,它正在计算&(null_pointer->m),这不会导致崩溃。

答案 6 :(得分:-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 ++的方法完全相同