4 ms·
TIL `a ?: b`, that's actually pretty nice, a bit like Haskell's `fromMaybe b a` (or `a <|> b` if b can also b "empty") and I do like `#define _(e...) ({e;})` –
by internet_points 11mo ago
TIL `a ?: b`, that's actually pretty nice, a bit like Haskell's `fromMaybe b a` (or `a <|> b` if b can also b "empty")
and I do like `#define _(e...) ({e;})` – that's one where I feel the short macro name is OK. But I'd like it better if that were just how C worked from the get-go.
Very nice discussion at the end of the article. There are good things to be learnt from this code and its discussions even if you disagree with some or even most of the style.
- susam 11mo agoYes, '?:' is also known as the Elvis operator [1][2]. I sometimes use it in other languages such as Groovy. But I don't use it in C because this happens to be a GCC extension [3][4] and I've often had to compile my C projects with compilers that do not support GCC extensions. The C standard [5] defines the conditional operator as: conditional-expression: logical-OR-expression logical-OR-expression ? expression : conditional-expression So per the C standard there must be an expression between '?' and ':' and an expression cannot be empty text. To confirm this we need to check the grammar for expression, which unfortunately is a little tedious to verify manually due to its deeply nested nature. Here it is: expression: assignment-expression expression , assignment-expression assignment-expression: conditional-expression unary-expression assignment-operator assignment-expression unary-expression: postfix-expression ++ unary-expression -- unary-expression unary-operator cast-expression sizeof unary-expression sizeof ( type-name ) alignof ( type-name ) assignment-operator: one of = *= /= %= += -= <<= >>= &= ^= |= ... and so on ... The recursion goes further many more levels deep but the gist is that no matter whichever branch the parser takes, it expects the expression to have at least one symbol per the grammar. Perhaps an easier way to confirm this is to just have the compiler warn us about it. For example: $ cat foo.c int main(void) { if () {} } $ clang -std=c17 -pedantic -Wall -Wextra foo.c && ./a.out foo.c:2:9: error: expected expression 2 | if () {} | ^ 1 error generated. Or more explicitly: $ cat bar.c #include <stdio.h> int main(void) { printf("%d\n", 0 ?: 99); printf("%d\n", 1 ?: 99); } $ clang -std=c17 bar.c && ./a.out 99 1 $ clang -std=c17 -pedantic bar.c && ./a.out bar.c:3:23: warning: use of GNU ?: conditional expression extension, omitting middle operand [-Wgnu-conditional-omitted-operand] 3 | printf("%d\n", 0 ?: 99); | ^ bar.c:4:23: warning: use of GNU ?: conditional expression extension, omitting middle operand [-Wgnu-conditional-omitted-operand] 4 | printf("%d\n", 1 ?: 99); | ^ 2 warnings generated. 99 1 [1] https://kotlinlang.org/docs/null-safety.html#elvis-operator https://kotlinlang.org/docs/null-safety.html#elvis-operator [2] https://groovy-lang.org/operators.html#_elvis_operator https://groovy-lang.org/operators.html#_elvis_operator [3] https://gcc.gnu.org/onlinedocs/gcc/Syntax-Extensions.html https://gcc.gnu.org/onlinedocs/gcc/Syntax-Extensions.html [4] https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html [5] https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3299.pdf https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3299.pdf