I want to write an all inclusive compiler warning message macro. How can you define such a macro to write out a warning given a certain compiler.
The standard for writing warnings is #pragma message "warning" which you can define in a macro using _Pragma, but when it comes to something like Keil you have to use #warning and a macro cannot be defined using _Pragma seeing as #pragma will precede the macro argument and Keil does not recognise #prama warning.
#if defined(__GNUC__)
#define PRAGMA(x) _Pragma(#x)
#define COMP_MSG(msg)\
PRAGMA(message msg)
#elif defined(__ARMCC_VERSION)
// need code here
#endif
COMP_MSG("WARNING")
This simple code:
#define WIDTH 500.5
#define NB 23.2
int x[(int)(WIDTH/NB)];
gives me a warning:
prog.c:4:1: warning: variably modified 'x' at file scope [enabled by default]
If I set #define WIDTH 500 and #define NB 23, the warning disappears.
Passing a float value for WIDTH macro forces evaluation by the compiler and thus issues a warning because array has not a constant size.
The preprocessed C code looks like int x[(int)(500.5/23.2)];, whereas int x[(int)(500/23)]; is OK for the compiler (value is already constant integer)
I would like to find a way either
to ignore this particular warning (but leaving the others so I can enable -Werror: seems that is a lost cause: GCC, C: Finding out name of default warnings for use in #pragma ignore
fix the code so it does what I want without issuing warnings.
force the pre-processor to perform the computation as integer
Funny thing: compiling with g++ I don't have the warning whereas I read here that variable length arrays are not officially supported in C++, only in C99. But that's not an option for me, since I need to stick to C.
It just violates the standard:
Integer constant expression
An integer constant expression is an
expression that consists only of operators other than assignment,
increment, decrement, function-call, or comma, except that cast
operators can only cast arithmetic types to integer types, integer
constants, enumeration constants, character constants, floating
constants, but only if they are immediately used as operands of casts
to integer type
And further:
The following contexts require expressions that are known as integer
constant expressions':
...
The index in an array designator (since C99)
One could ensure that a normal array (non VLA) is created like this:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
enum{ARRAY_DIMENSION_OF_x = (int)(WIDTH/NB)};
int x[ARRAY_DIMENSION_OF_x];
#pragma GCC diagnostic pop
This compiles without warning in gcc and clang in C mode and with a old-style cast to 'int' warning in C++ mode.
One could also hide the creation of the enum within a macro:
/* ================= define MAKE_CONST_INT() macro ================= */
#ifdef __cplusplus
template<class T> struct make_const_int_helper{static T t;};
# define MAKE_CONST_INT(x) (sizeof(*(make_const_int_helper<char (*)[int((x)+0L)]>::t))) /* +0L avoids "useless cast" warning*/
#else
# define EVALUATE_TO_0(type) (0*__builtin_types_compatible_p(type,int))
# define EVALUATE_TO_0_PRAGMA(x) EVALUATE_TO_0(struct{int dummy; _Pragma(x)})
# define EVALUATE_TO_0_START_DISABLE_WARNINGS \
( EVALUATE_TO_0_PRAGMA("GCC diagnostic push") \
+ EVALUATE_TO_0_PRAGMA("GCC diagnostic ignored \"-Wpedantic\"") \
+ EVALUATE_TO_0_PRAGMA("GCC diagnostic ignored \"-Wc++-compat\"") )
# define EVALUATE_TO_0_END_DISABLE_WARNINGS \
EVALUATE_TO_0_PRAGMA("GCC diagnostic pop")
# define MAKE_CONST_INT(x) MAKE_CONST_INT_HELPER2(x,__LINE__,__COUNTER__)
# define MAKE_CONST_INT_HELPER2(x,line,counter) MAKE_CONST_INT_HELPER(x,line,counter)
# define MAKE_CONST_INT_HELPER(x,line,counter) \
( EVALUATE_TO_0_START_DISABLE_WARNINGS \
+ EVALUATE_TO_0(enum{ INT_CONSTANT_##counter##_AT_LINE_##line = (int)(x) }) \
+ INT_CONSTANT_##counter##_AT_LINE_##line \
+ EVALUATE_TO_0_END_DISABLE_WARNINGS)
#endif
/* ================= test MAKE_CONST_INT() macro ================= */
#define WIDTH 500.5
#define NB 23.2
extern int x[MAKE_CONST_INT(WIDTH/NB)];
This compiles without warning in gcc and clang in C and in C++ mode.
The structs with the int dummy members are only necessary to get a place where gcc accepts a _Pragma("GCC diagnostic ....") pragma.
Example
Extended implementation that works for MSVC, gcc, clang and icc, but still won't compile on really picky compilers:
/* ================= define MAKE_CONST_INT() macro ================= */
#ifdef __cplusplus
# if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wtemplates"
# endif
template<class T> struct make_const_int_helper{static T t;};
# if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic pop
# endif
# define MAKE_CONST_INT(x) (sizeof(*(make_const_int_helper<char (*)[int((x)+0L)]>::t))) /* +0L avoids "useless cast" warning*/
#else
# if defined(__GNUC__)
# define EVALUATE_TO_0(type) (0*__builtin_types_compatible_p(type,int))
# define EVALUATE_TO_0_PRAGMA(x) EVALUATE_TO_0(struct{int dummy; _Pragma(x)})
# define EVALUATE_TO_0_START_DISABLE_WARNINGS \
( EVALUATE_TO_0_PRAGMA("GCC diagnostic push") \
+ EVALUATE_TO_0_PRAGMA("GCC diagnostic ignored \"-Wpedantic\"") \
+ EVALUATE_TO_0_PRAGMA("GCC diagnostic ignored \"-Wc++-compat\"") )
# define EVALUATE_TO_0_END_DISABLE_WARNINGS \
EVALUATE_TO_0_PRAGMA("GCC diagnostic pop")
# else
# define EVALUATE_TO_0(type) (0*sizeof(type))
# if defined(_MSC_VER)
# define EVALUATE_TO_0_START_DISABLE_WARNINGS \
(0 __pragma(warning( push )) __pragma(warning(disable:4116)))
# define EVALUATE_TO_0_END_DISABLE_WARNINGS (0 __pragma(warning( pop )) )
# else
# define EVALUATE_TO_0_START_DISABLE_WARNINGS 0 /*other compilers will not disable warning*/
# define EVALUATE_TO_0_END_DISABLE_WARNINGS 0
# endif
# endif
# define MAKE_CONST_INT(x) MAKE_CONST_INT_HELPER2(x,__LINE__,__COUNTER__)
# define MAKE_CONST_INT_HELPER2(x,line,counter) MAKE_CONST_INT_HELPER(x,line,counter)
# define MAKE_CONST_INT_HELPER(x,line,counter) \
( EVALUATE_TO_0_START_DISABLE_WARNINGS \
+ EVALUATE_TO_0(enum{ INT_CONSTANT_##counter##_AT_LINE_##line = (int)(x) }) \
+ INT_CONSTANT_##counter##_AT_LINE_##line \
+ EVALUATE_TO_0_END_DISABLE_WARNINGS)
#endif
/* ================= test MAKE_CONST_INT() macro ================= */
#define WIDTH 500.5
#define NB 23.2
extern int x[MAKE_CONST_INT(WIDTH/NB)];
Here one example from GNU GCC that can help you:
#pragma GCC diagnostic error "-Wuninitialized"
foo(a); /* error is given for this one */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuninitialized"
foo(b); /* no diagnostic for this one */
#pragma GCC diagnostic pop
foo(c); /* error is given for this one */
#pragma GCC diagnostic pop
foo(d); /* depends on command-line options */
I am trying to write some library code that may be used by people who have pthreads enabled (or not), and by people who have openmp support (or not). I have some variable that I really want to be in thread-local storage. Is there any potential harm in specifying this twice, for example
#ifdef __GNUC__
# define PREFIX __thread
#elif __STDC_VERSION__ >= 201112L
# define PREFIX _Thread_local
#elif defined(_MSC_VER)
# define PREFIX __declspec(thread)
#else
# define PREFIX
#endif
PREFIX int var = 10;
#pragma omp threadprivate(var)
(Note, the business to figure out the TLS prefix is taken from How to declare a variable as thread local portably?)
I know this works on my system (Debian with recent gcc) but it's hard to know whether things could go wrong elsewhere since these compiler-specific declarations are not part of the OpenMP standard.
What about:
#if __STDC_VERSION__ >= 201112L
# define PREFIX _Thread_local
#elif defined(__GNUC__)
# define PREFIX __thread
#elif defined(_MSC_VER)
# define PREFIX __declspec(thread)
#else
# define PREFIX
#endif
PREFIX int var = 10;
#if !PREFIX
#ifdef _OPENMP
#pragma omp threadprivate(var)
#else
#error "Failure to put variable into TLS"
#endif
#endif
GCC doesn't mind the over-specifying because __thread is an implicit #pragma omp threadprivate anyway.
Instead of worrying about compilers where this might not be the case, just use OpenMP's threadprivate conditionally.
How can I get GCC or Clang to warn me about the error below, where M was supposed to be N in line 2?
Even with -Wall -Wextra -Wunknown-pragmas, none of these compilers emit any sort of warning.
#define N 4
#pragma pack(push, M)
int main() {
return 0;
}
#pragma pack(pop)
The compiler cannot know your intentions, only if the code is valid. You can check up on yourself with this
#ifndef M
#error M not defined
#endif
Or if M was defined separately from N with this
#if M != N
#error M is not N
#endif
If you look at the output of the preprocessor the pragma is not evaluated ie if you add N you won't get a 4 after the preprocessor is done.
I don't think you can have it warn here, at least not easily, maybe a preprocessor wizard might be able to figure it out. The following warning does not help unless it's in an undefined value in an #if statement.
-Wundef
If you try and add anything to the pragma ie
#pragma pack(push, (M + 0))
You get a warning because the pragma is expecting an integer or identifier ie
warning: expected integer or identifier in '#pragma pack'
I have the same problem as described by Jonathon Reinhart here:
Temporarily disable gcc warning on redefinition
That is because I have to use thrid party libraries (C only) which throws tons of warnings like this
Warning "__always_inline" redefined [enabled by default]
What I want is something like this:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-W???"
#include "someheader.h"
#include "otherheader.h"
#pragma GCC diagnostic pop
Is there a way to disable warnings by gcc which are enabled by default with a
#pragma GCC diagnostic ignored
EDIT:
here is the block causing the warning (file: compiler.h):
#if defined(__CC_ARM)
# define __always_inline __forceinline
#elif (defined __GNUC__)
# define __always_inline inline __attribute__((__always_inline__))
#elif (defined __ICCARM__)
# define __always_inline _Pragma("inline=forced")
#endif
I fixed it by undefining all lines where __always_inline was defined. :-(
Thanks Jasen for helping!