8

我遇到了一些 C 代码,它们使用引用/取消引用(或您选择的任何名称)运算符,*并且&同时像&*fooand *&bar。我对此感到困惑。有什么理由这样做吗?

4

3 回答 3

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
}
于 2016-07-01T19:10:33.753 回答
2
于 2016-07-01T19:12:04.233 回答
0
  1. &*ptr包含对编译器的提示ptr != NULL(否则*ptr将意味着未定义的行为)。

  2. *&可能只是维护更改的结果,其中删除了辅助指针变量:

    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;  // <---
        ...
    }
    
  3. 类似地&*,可以通过用指针替换左值的重构更改引入。

    重构前:

    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);
        ...
    }
    
于 2016-07-03T20:29:22.307 回答