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.