I'm trying to define a macro to return the result of a range check which works on signed and unsigned types. However, because I am compiling with -Wextra
which includes -Wtype-limits
, I want to ignore -Wtype-limits
just for this macro. Unfortunately, this:
#define IN_RANGE(v, min, max) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
( (((v) < (max)) && ((v) > (min))) ? true : false ) \
_Pragma("GCC diagnostic pop")
Fails to compile (because I'm also using -Werror
) with:
... error: expected expression before '#pragma'
[build] 40 | _Pragma("GCC diagnostic push") \
[build] | ^~~~~~~
Edit: here's a complete example.
#include <stdio.h>
#include <stdint.h>
#define IN_RANGE(v, min, max) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
( (((v) < (max)) && ((v) > (min))) ? true : false ) \
_Pragma("GCC diagnostic pop")
const uint32_t MIN_NUM = 0;
const uint32_t MAX_NUM = 10;
int main() {
printf("%s", IN_RANGE(8, MIN_NUM, MAX_NUM) ? "OK": "FAIL");
return 0;
}
Fails with (on gcc 9):
$ gcc -Wall -Wextra example.c
example.c: In function ‘main’:
example.c:14:1: error: expected expression before ‘#pragma’
14 | printf("%s", IN_RANGE(8, MIN_NUM, MAX_NUM) ? "OK": "FAIL");
| ^ ~
Given some experimentation, it seems that you can't just embed the
_Pragma()
operator in the middle of an expression. In effect, it needs to be used where a statement can be used.This code compiles, and AFAICT it is because there's a complete statement sandwiched between the
_Pragma()
operators:Note the semicolon before the third
_Pragma()
operator. Without that, I was gettingexpected ‘;’ before ‘#pragma’
(as an error since I too compile with-Werror
).I've also simplified the conditional so it doesn't use the ternary operator, as I noted in a comment.
The relevant section of the standard is §6.10.9 Pragma operator. It says:
Think about what the code expands to in your example:
is approximately equivalent to:
This doesn't compile. It produces the error:
Line 12 is the first
#pragma
directive.I'm not totally convinced that this is what the standard mandates, but it is what I get from GCC 11.2.0.
However, when I compile with Apple's Clang (
Apple clang version 14.0.0 (clang-1400.0.29.202)
), both versions of the code I show compile OK. Thus, there is a discrepancy in the interpretation of the standard between these two major C compilers.And, indeed, when I compile with Clang, your original code compiles cleanly. You can probably make a case out for a bug report to the GCC team. However, if you're going to write portable code, you'll need to accept the limitations imposed by GCC for a few years yet (though that depends on your portability requirements).