Home > Mobile >  C - How to use multiple functions in macros?
C - How to use multiple functions in macros?

Time:03-07

Currently building a simple webserver in c. To improve the code I want to use makros and spefically I want to use multiple functions inside a single makro to print an error message and quit the program afterwards.

The following code works without pedantic error messages but I would like to know why ISO-C forbids this or where my error is.

Compiler info:

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

Code:

#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 message:

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");
      |     ^~~~~

CodePudding user response:

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

will work:

https://godbolt.org/z/Kxed3b55r

Both sides have the same type void. You cannot use -pedantic as compile time flag, because ISO C forbids braced-groups within expressions.

In this case I would suggest:

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

https://godbolt.org/z/srExevfGT

CodePudding user response:

In standard C, the ; marks the end of an expression. Therefore a parenthesis cannot contain a ;, since syntax-wise a both ( and ) of the parenthesis needs to be inside a full expression.

The ({ ... }) is a "statement expression", a non-standard GNU extension that allows multiple expressions ending with ; inside it and at the same time returning the result of the last expression.

In -std=c17 -pedantic mode, gcc turns into a compliant C compiler so all GNU extensions are disabled.

Please note that standard C can likely be used instead of these "statement expressions". You can often chain a bunch of function calls using the comma operator: (perror(m), exit(1)) - this too returns the result of the last (right-most) sub-expresion.

Better yet, use an actual function, which is probably the most correct solution in this case.

  • Related