我遇到过一些C代码,它们同时使用引用/解除引用(或者你选择的任何名称)运算符*
和&
,例如{{ 1}}和&*foo
。我很困惑。有什么理由这样做吗?
答案 0 :(得分:15)
是的,可以有意义地使用它们:宏定义中的有效用例可以检查宏参数是否符合要求。
&*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
}
答案 1 :(得分:2)
这样做的唯一有意义的理由是停止将表达式视为左值。
引用C11
,章节§6.5.3.2
一元
&
运算符生成其操作数的地址。如果操作数的类型为''type'', 结果有''指向类型''的指针。如果操作数是一元*
运算符的结果, 该运算符和&
运算符都不会被评估,结果就像两者都一样 省略,除了对运算符的约束仍然适用且结果不是左值。
答案 2 :(得分:0)
&*ptr
包含ptr != NULL
编译器的提示(否则*ptr
将表示未定义的行为)。
*&
可能只是维护更改的结果,其中消除了辅助指针变量:
struct {
int i;
double
} x;
void foo() {
int* ip = &x.i;
...
*ip = 1;
...
}
使用ip
直接替换上面的代码&x.i
会导致代码在StackOverflow上产生这样的问题:
struct {
int i;
double
} x;
void foo() {
...
*&x.i = 1; // <---
...
}
类似地,&*
可能会通过重构更改引入,该更改将lvalue替换为指针。
重构之前:
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);
...
}