Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics

Dashboard
Notifications
Mark all as read
Q&A

Scheme for cross-platform warning control?

+8
−0

tl;dr I'd like to learn a compact, cross-compiler way of selectively suppressing compiler warnings.


Consider the case where you really mean to make an exact floating-point comparison using ==, or the case where you capture a return value that you don't use in production but want to assert on in debug.

If you are running your compiler with a highly level of feedback you're going to get a warnings from the first all the time and from the second when performing a release build.

Now, most compilers have a way to annotate a symbol to let the compiler know you're aware of the situation (for instance __attribute__((unused)) in gcc), and various pre-processor pragmas to adjust the compilation envrionment. But we have three compilers to worry about (gcc and msvc for actually building the code on different target platforms and clang as a linter on both).

In some places we actually have painfully heavy and intrusive pre-processor constructs like:

#if defined(_MSC_VER)
#pragma warnings(push)
#pramga warnings(disable : 123456)
#elif defined(__clang__)
#pragma clang diagnostic push
#pramga clang diagnostic ignored "-Wluggage-combination"
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pramga GCC diagnostic ignored "-Wcode-for-my-luggage"
#endif

    // Offending line(s) of code

#if defined(_MSC_VER)
#pragma warnings(pop)
#elif defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#endif

Which, though ugly as sin, works and doesn't cause too much nausea if it occurs once in a low-level module that you don't touch often.

But I feel that it should be easier and neater.

Anyone have a working solution?

Why does this post require moderator attention?
You might want to add some details to your flag.
Why should this post be closed?

4 comments

Compiler warnings are... compiler-specific :) You should probably manage these through different builds per compiler, if possible, keeping everything in IDE project settings or make files. Asserts in particular should be handled with debug vs release builds. As for exact floating point comparison, consider using memcmp instead of ==. Lundin‭ about 1 month ago

@Lundin Using memcmp changes the semantics (NaNs can compare equal...) so you need to think about what you intend. We actually have a namespace where we define various classes of floating point comparisons (and use the abhorrent mess above in the implementation for fp::exactlyEqual) so that the code can express intent in words. dmckee‭ about 1 month ago

@dmckee Nan is going to be a special case no matter what you do. Lundin‭ about 1 month ago

One option I used in the past is a custom preprocessor that the building system calls before passing the resulting file to the compiler. Ringi‭ about 1 month ago

1 answer

+5
−0

Since C++11 the standard mandates the _Pragma operator which is intended for use inside macros.

With this you can improve the situation by wrapping all this compiler switching into a central macro definition (MSVC is untested!):

// see https://stackoverflow.com/a/45783809
#define DO_PRAGMA_(x) _Pragma (#x)
#define DO_PRAGMA(x) DO_PRAGMA_(x)

#define PUSH_WARNING_STATE DO_PRAGMA(warnings(push)) \
                           DO_PRAGMA(clang diagnostic push) \
                           DO_PRAGMA(GCC diagnostic push)

#define POP_WARNING_STATE DO_PRAGMA(warnings(pop)) \
                          DO_PRAGMA(clang diagnostic pop) \
                          DO_PRAGMA(GCC diagnostic pop)

#define DISABLE_WARNING(WARNING_NAME) DO_PRAGMA(warnings(disable :  WARNING_NAME##_MSC) ) \
                                      DO_PRAGMA(clang diagnostic ignored WARNING_NAME##_CLANG) \
                                      DO_PRAGMA(GCC diagnostic ignored WARNING_NAME##_GCC)

Which can be used like:

// find some custom central naming for your warnings
#define WARN_UNINITIALIZED_CLANG "-Wuninitialized"
#define WARN_UNINITIALIZED_GCC "-Wuninitialized"

int main(int argc, char **argv) {
        float a = 0, b;
        PUSH_WARNING_STATE
        DISABLE_WARNING(WARN_UNINITIALIZED);
        if(a != b) {
                POP_WARNING_STATE
                return a == b;
        }
}

Compiling gives only the second error, as intended:

$ g++ -Wall -pedantic test.cpp 
test.cpp: In function 'int main(int, char**)':
test.cpp:39:12: warning: 'b' may be used uninitialized in this function [-Wmaybe-uninitialized]
   39 |   return a == b;
      |          ~~^~~~

Limitations:

  • problem with warnings that can only be disabled on some platforms (-> pragma might trigger a warning)
Why does this post require moderator attention?
You might want to add some details to your flag.

5 comments

Every time I think I know this language someone comes along and shows me another corner I've never heard of. Thanks. dmckee‭ about 1 month ago

Well, even in old school C you can simply use #pragma without any surrounding #ifdef. Compilers are supposed to simply ignore unknown pragmas and not whine about "unknown pragma". Lundin‭ about 1 month ago

@Lundin Should have thought about this a bit longer. This gets rid of the whole ifdef switching. Someone‭ about 1 month ago

It should get rid of the switches, but I started using that nonsense because MSVC was warning me about unfamiliar #pragma’s. dmckee‭ about 1 month ago

@dmckee‭ Yeah it sucks that various compilers decide to whine about that. It's like they never understood what #pragma is supposed to do in the first place. Lundin‭ about 1 month ago

Sign up to answer this question »