C - 如何在宏中使用多个函数?

C - How to use multiple functions in macros?

目前正在用 c 构建一个简单的网络服务器。 为了改进我想使用 makros 的代码,特别是我想在单个 makro 中使用多个函数来打印错误消息并随后退出程序。

下面的代码没有迂腐的错误信息,但我想知道为什么 ISO-C 禁止这个或者我的错误在哪里。

编译器信息:

gcc -O0 -g3 -pedantic -pedantic-errors -Wall -Wextra -Werror error_makro.c

代码:

#define CHECK(x,m) ((x) < 0) ? ({perror(m); exit(1);}) : (NULL)

void createWebSocket(simpleWebServer *self){

    struct addrinfo hints, *res;
    memset(&hints, 0, sizeof(hints));

    hints.ai_family = AF_UNSPEC;
    hints.ai_flags = AI_PASSIVE;
    hints.ai_socktype = SOCK_STREAM;


    CHECK(getaddrinfo(NULL, self->port, &hints, &res), "getaddrinfo");

    if((self->serverSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0){
        perror("socket");
        exit(2);
    }
    if(bind(self->serverSocket, res->ai_addr, res->ai_addrlen) < 0){
        perror("bind");
        exit(3);
    }
    if(listen(self->serverSocket, BACKLOG) == -1){
        perror("listen");
        exit(4);
    }
    freeaddrinfo(res);  
}

错误信息:

error_makro.c: In function ‘main’:
error_makro.c:6:32: error: ISO C forbids braced-groups within expressions [-Wpedantic]
    6 | #define CHECK(x,m) ((x) < 0) ? ({perror(m); exit(1);}) : (NULL)
      |                                ^
error_makro.c:11:5: note: in expansion of macro ‘CHECK’
   11 |     CHECK(-1, "test");
      |     ^~~~~
error_makro.c:6:56: error: ISO C forbids conditional expr with only one void side [-Wpedantic]
    6 | #define CHECK(x,m) ((x) < 0) ? ({perror(m); exit(1);}) : (NULL)
      |                                                        ^
error_makro.c:11:5: note: in expansion of macro ‘CHECK’
   11 |     CHECK(-1, "test");
      |     ^~~~~
#define CHECK(x,m) ((x) < 0) ? ({perror(m); exit(1);}) : ({(NULL);})

将工作:

https://godbolt.org/z/Kxed3b55r

双方类型相同void。您不能使用 -pedantic 作为编译时标志,因为 ISO C forbids braced-groups within expressions.

在这种情况下我建议:

#define CHECK(x,m) do { if ((x) < 0) {perror(m); exit(1);} } while (0)

https://godbolt.org/z/srExevfGT

在标准 C 中,; 标记表达式的结束。因此括号不能包含 ;,因为 syntax-wise 括号的 () 都需要在完整表达式中。

({ ... })是一个“语句表达式”,一个non-standard GNU扩展,允许多个以;结尾的表达式在里面同时返回最后一个的结果表达式。

-std=c17 -pedantic 模式下,gcc 变成兼容的 C 编译器,因此所有 GNU 扩展都被禁用。

请注意,很可能会使用标准 C 来代替这些“语句表达式”。您通常可以使用逗号运算符链接一堆函数调用:(perror(m), exit(1)) - 这也是 returns 最后一个 (right-most) sub-expresion.

的结果

更好的是,使用实际函数,在这种情况下这可能是最正确的解决方案。