我遇到一些C代码,利用引用/解引用(或任何你选择叫他们)操作符,*
和&
,在同一时间,像&*foo
和*&bar
。我对此感到困惑。有什么理由这样做吗?
是的,它们可以被有意义地使用:一个有效的用例是在宏定义中检查宏参数是否与需求匹配。
&*foo
验证foo
是指针类型(可能经过数组或函数类型的隐式转换)。
*&foo
验证foo
是左值表达式
例如,不可否认,这个例子太简单了,可能有点滥用宏:
void f(int *);
#define F(x) (f(&*(x)))
void g(int *);
#if A
#define G(x) (g(x), (x)=0)
#elif B
#define G(x) (g(*&(x)))
#endif
void h(int *p, int i) {
f(p); // okay
F(p); // still okay, does the same thing as f(p)
f(i); // typically just a compiler warning
F(i); // pretty much always a compiler error
g(p); // okay
G(p); // okay
g(p+0); // okay
G(p+0); // error if A because of the modification
// should be an error if B even without modification
}
这样做的唯一有意义的原因是停止将表达式视为左值。
引用C11
, chapter§6.5.3.2
一元
&
运算符返回其操作数的地址。如果操作数的类型为 " type " ,结果类型为 "指向类型" 的指针"。如果操作数是一元*
操作符的结果,既不计算该操作符,也不计算&
操作符,结果就好像两者都计算了一样
-
&*ptr
向编译器提示ptr != NULL
(否则*ptr
将意味着未定义行为)。 -
*&
可能只是一个维护更改的结果,其中一个辅助指针变量被消除了:struct { int i; double } x; void foo() { int* ip = &x.i; ... *ip = 1; ... }
在上面的代码中直接用
&x.i
替换ip
会导致在StackOverflow上产生这样的问题:struct { int i; double } x; void foo() { ... *&x.i = 1; // <--- ... }
-
同样,
重构前&*
也可以通过重构更改来引入,将左值替换为指针。:
int main() { struct sockaddr_in serv_addr; ... bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); ... }
将服务器设置代码提取到自己的函数中:
void setup_server(struct sockaddr_in* serv_addr) { ... bind(sockfd, (struct sockaddr *) &*serv_addr, sizeof(*serv_addr)); ... } int main() { struct sockaddr_in serv_addr; ... setup_server(&serv_addr); ... }