C语言 这两种设置指针相等的方法是否相同?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16900614/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Are these two methods for setting pointers equal to each other the same?
提问by user1876508
I am curious, if I have two pointers
我很好奇,如果我有两个指针
int *x = (int *)malloc(sizeof(int));
int *y;
and I want y to point to the address of x, is
我想让 y 指向 x 的地址,是
y = x;
the same as
一样
y = &*x;
?
?
回答by Mike
Your question has two parts, and it's worth noting that they are not both correct:
你的问题有两部分,值得注意的是,它们并不都是正确的:
First, you ask:
首先,你问:
is
y = x;
the same as
y = &*x;
是
y = x;
与
y = &*x; 相同
Since the dereference (*) and address-of (&) operators have the same precedencethey will bind right to left, so
由于解引用 ( *) 和 address-of ( &) 运算符具有相同的优先级,它们将从右到左绑定,因此
y = &*x;
is the same as:
是相同的:
y = &(*x);
And yes, that will yield the same effect as y=x;Now if you have a C compliant compiler that follows the letter of the law, it will not only be the same effectively, it willbe the same, this is due to section 6.5.3.2 P3 of the C Specification:
是的,这将产生同样的效果y=x;,如果你有一个C编译器兼容下面的法律条文有效现在,它不仅是相同的,这将是相同的,这是由于部分6.5.3.2 P3 C规范的:
The unary & operator yields the address of its operand. If the operand has type ‘‘type'', the result has type ‘‘pointer to type''.
If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted
一元 & 运算符产生其操作数的地址。如果操作数的类型为“type”,则结果的类型为“指向类型的指针”。
如果操作数是一元 * 运算符的结果,则该运算符和 & 运算符都不计算,结果就好像两者都被省略了
So the compiler will see both the *and &together and omit them entirely.
所以编译器会同时看到*和&并完全省略它们。
In the second half of your question you stated:
在你问题的后半部分,你说:
I want y to point to the address of x
I want y to point to the address of x
Presumably you know that that's not what you're doing, but you're setting yto point to the same addressas xinstead. xof course has its own address and that could be set, but you'd need a different variable int **y = &x;assuming xis a valid value to be dereferenced.
想必你知道,这不是你在做什么,而是你设置y到指向相同的地址作为x代替。x当然有自己的地址并且可以设置,但是int **y = &x;假设x是要取消引用的有效值,您需要一个不同的变量。
回答by Cloud
They are functionallyequivalent. This is effectively a "shallow copy".
它们在功能上是等效的。这实际上是一个“浅拷贝”。
So, the following assignments achieve the same final result:
因此,以下作业获得了相同的最终结果:
y=x;
y=&(*x);
However, the second operation will take more time to execute because rather than just a direct assignment, you are performing an indirectionthen an address-ofoperation. The compiler may just optimize this down to y=xanyways, depending on your system.
但是,第二个操作将花费更多时间来执行,因为您执行的不仅仅是直接赋值,而是执行间接寻址,然后是寻址操作。y=x根据您的系统,编译器可能只是将其优化为无论如何。
Edit:
编辑:
As the poster below notes, if your compiler supports the C standard, including 6.5.3.2 P3 of the C standard, this will definitely be optimized out, likely at the pre-processor level before the code is even compiled.
正如下面的海报所指出的,如果您的编译器支持 C 标准,包括 C 标准的 6.5.3.2 P3,这肯定会被优化,甚至可能在编译代码之前在预处理器级别进行优化。
回答by Keith Thompson
They are either exactly the same by definition, or almost the same, depending on which version of the C standard you're dealing with.
它们的定义要么完全相同,要么几乎相同,具体取决于您处理的是哪个版本的 C 标准。
In ISO C99 and C11, we have the following wording (quoting the N1570C11 draft) in 6.5.3.2:
在 ISO C99 和 C11 中,我们在 6.5.3.2 中有以下措辞(引用N1570C11 草案):
The unary
&operator yields the address of its operand. If the operand has type "type", the result has type "pointer to type". If the operand is the result of a unary*operator, neither that operator nor the&operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue.
一元运算
&符产生其操作数的地址。如果操作数的类型为“ type”,则结果类型为“指向类型的指针”。如果操作数是一元运算*符的结果,则既不计算该运算符也不计算该&运算符,结果就像两者都被省略,除了运算符的约束仍然适用并且结果不是左值。
So given:
所以给出:
int *x = /* whatever */;
int *y;
these two are exactly equivalent, even if xis a null pointer:
这两个完全等效,即使x是空指针:
y = x;
y = &*x;
Without the special-case rule, the behavior would be undefined, because the behavior of the *operator is defined only if its operand is a valid non-null pointer. But since the *is never evaluated, it has no behavior here, defined or otherwise. (The fact that, unlike x, &*xis not an lvalue is not relevant here.)
如果没有特殊情况规则,行为将是未定义的,因为*运算符的行为仅在其操作数是有效的非空指针时才被定义。但是由于*从未评估过,因此它在此处没有任何行为,定义或其他方式。(与 不同x,&*x不是左值这一事实在此处无关紧要。)
And in C89/C90, that special-case rule had not yet been added, so the behavior of &*xisundefined if xis a null (or otherwise invalid) pointer. Most pre-C99 compilers would probably optimize away the *and &anyway; remember, it's the nature of undefined behavior that something canbehave just as you might expect it to behave.
而在 C89/C90 中,该特殊情况规则尚未添加,因此如果是空(或其他无效)指针,&*x则其行为未定义x。大多数 C99 之前的编译器可能会优化掉*和&;请记住,它是不确定的行为性质的东西可以表现得就像你可能会期望它的行为。
On the other hand, there's a very real difference in the behavior of anyone reading the code. If I see y = x;, my behavior is to think "Oh, it's an ordinary pointer assignment." If I see y = &*x;, my behavior is to think "Why the heck did you write it that way?", and to change it to y = x;if I'm in a position to do so.
另一方面,阅读代码的任何人的行为都有非常实际的差异。如果我看到y = x;,我的行为是想“哦,这是一个普通的指针分配”。如果我看到y = &*x;,我的行为是想“你到底为什么要那样写?”,然后将其更改为y = x;如果我可以这样做。
回答by Tom Tanner
Yes, although the second one looks like an entry for an obfuscation contest.
是的,虽然第二个看起来像是混淆竞赛的参赛作品。
回答by Geoffrey
Yes, they are the same, but highly convoluted.
是的,它们是相同的,但非常复杂。
You can test this by doing the following:
您可以通过执行以下操作来测试:
y = &(*x);
printf("%p\n", (void*)x);
printf("%p\n", (void*)y);
回答by anishsane
To my knowledge, they are exactly equivalent. I will be surprised if some compiler does treat them differently.
据我所知,它们完全等效。如果某些编译器确实以不同的方式对待它们,我会感到惊讶。
Because of presense of &, *xwill not be evaluated at all. Hence even if x is null, it will not cause crash / seg-fault. (You can best verify using assembly.)
由于存在&,*x根本不会进行评估。因此,即使 x 为空,也不会导致崩溃/段错误。(您最好使用汇编进行验证。)
When we talk of assembly, it's impossible to calculate *x (value) & then &(*x) (pointer). Hence, compiler will simply calculate the address of *x, without calculating value of *x.
当我们谈论汇编时,不可能计算 *x(值)& 然后是 &(*x)(指针)。因此,编译器只会计算 *x 的地址,而不计算 *x 的值。
We can also check for more complex cases, like &(a[10])It simply translates to a+10*sizeof(a[0])in assembly.
我们还可以检查更复杂的情况,比如&(a[10])它简单地转换为a+10*sizeof(a[0])汇编。
Another proof would be the offsetofmacro, typically defined as:
另一个证明是offsetof宏,通常定义为:
#define offsetof(st, m) ((size_t)(&((st *)0)->m))
Here, it's calculating &(null_pointer->m), which does not cause a crash.
在这里,它正在计算&(null_pointer->m),这不会导致崩溃。
回答by Steve Russell
Here is a handy little function that may help. Not sure that you need all of the "includes".
这是一个方便的小功能,可能会有所帮助。不确定您是否需要所有“包含”。
#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';
}
The result I get from this is:
我从中得到的结果是:
x has type: Pi
y has type: Pi
z has type: Pi
values are 0x1a3a010 0x1a3a010 0x1a3a010
The answer then is, Yes, the methods are exactly the same using Ubuntu 14.10, g++
答案是,是的,使用 Ubuntu 14.10、g++ 的方法完全相同

