Suppressing Warnings in GCC and Clang
There are at least 7 ways of how to suppress warnings in GCC and Clang. This article explains these 7 ways, which are writing different code, qualifiers and specifiers, attributes ([[ ]]
), __attribute__
, _Pragma
, #pragma
, and command line options.
TL;DR: If possible, write better code, otherwise, if possible, use qualifiers and specifiers, [[ ]]
, or __attribute__
, else use _Pragma
.
- Author:
- Christian Hujer, Software Crafter and CEO / CTO of Nelkinda Software Craft Private Limited
- First Published:
- by Nelkinda Software Craft Private Limited
- Last Modified:
- by Christian Hujer
- Approximate reading time:
1 Warnings
Ideally, we will write our source code in a way that it would not generate any compiler warnings. There are, however, some situations in which this is not possible. To name just a few:
- We have to implement an interface and do not need all of its parts, for example not all function arguments.
- We get conflicting warnings from different compilers.
There are at least 7 different ways how to deal with compiler warnings in GCC and Clang:
- Writing different source code
- Using qualifiers and specifiers to provide more information to the compiler
- Using standard attributes
[[ ]]
to provide more information to the compiler - Using legacy
__attribute__
to provide more information to the compiler - Using
_Pragma
to suppress the warning - Using
#pragma
to suppress the warning - Using command line options to suppress the warning
2 Sample Project
I want to showcase all 7 different ways how to deal with compiler warnings in GCC and Clang. For that, I will use the following sample project.
When compiling using make
, we get the following error message:
The parameter argc
of function main
is not used. We can, however, not drop it, as this would be against the C and POSIX specifications. And both, GCC and Clang, know that. You would get -Werror=main
warnings if you try to remove argc
from the signature.
3 Addressing Warnings
3.1 Writing Different Source Code
One way to avoid warnings is to write different source code. In general, avoiding warnings by writing better source code is the preferable way. But note the subtle difference between the words different and better. Source code is not necessarily better just because it's different, even if it produces fewer warnings. This is an excellent example for one of those rare situations where different with fewer warnings does not mean better.
This compiles just fine with make
. But the for
-loop is more complex than the previous while
loop. And at least on an AMD64 instruction set, GCC and Clang will emit bigger, more complex code. Discussing the details of this is a story for a different time. But in this case, the for
loop is not better than the while
loop. We've made the code worse just to get rid of a compiler warning, which is not good.
If your code gets better when getting rid of a compiler warning, changing the source code is the way to go. If you can't find a way of how to get rid of a compiler warning by making the code better, you need other options.
Writing different source code is a potential risk. How do you know that the different code behaves the same way as the old code? You could possibly introduce bugs, so be careful. Best, have tests which will cover your change.
3.2 Suppressing Warnings by Giving the Compiler more Information
As we could see, changing the source code does not always lead to better solutions. Other approaches are required.
C compilers cannot have a holistic knowledge and understanding of a software project. The feedback they give is based on the input files only, nothing else. Some compiler warnings would go away if we would give the compiler more information.
3.2.1 Standard Qualifiers and Specifiers
The C language defines a number of specifiers which programmers can use to give the compiler more information. const
and _Noreturn
are such examples. By taking a closer look at the C language, you may discover a keyword that's use will do two things: Make your source code more correct, and because of that, also remove the warning that you're looking at.
You can read more about const
, _Noreturn
and other qualifiers and specifiers in the Programming Languages — C specification.
3.2.2 Standard C++11 / C2x Attributes [[ ]]
In the latest version C2x, the standard added a way for specifying attributes, as well as a set of predefined standard attributes. These are: [[deprecated]]
, [[fallthrough]]
, [[maybe_unused]]
, and [[nodiscard]]
.
Attributes will not really suppress a warning. With attributes, we can give the compiler information to understand certain aspects of our source code better. This better understanding can make a warning go away.
In this case, we want to tell the compiler that the parameter argc
is not used. So we add [[maybe_unused]]
to the declaration of the parameter argc
.
If an attribute is used frequently, it can be useful to declare a macro for it. The macro can also be useful if you need to deal with different compilers and some of them do not support the C2x attribute syntax. I name the macro A_Unused
and think of it in a similar way as annotations in languages like Java.
You can read more about attributes in the Programming Languages — C specification.
3.2.3 __attribute__
The information that we want to give to the compiler may not (yet) be supported by the C standard. Compilers can implement their own ways of how to provide additional information. In the case of GCC and Clang, that is __attribute__
.
__attribute__
will not really suppress a warning. With __attribute__
, we can give GCC and Clang information to understand our source code better. And with that better understanding, a warning can go away.
In this case, we want to tell GCC and Clang that the parameter argc
is not used. So we add __attribute__((unused))
to the declaration of the parameter argc
.
If an attribute is used frequently, it can be useful to declare a macro for it. The macro can also be useful if you need to deal with different compilers and some of them do not support __attribute__
. I name the macro A_Unused
and think of it in a similar way as annotations in languages like Java.
A macro can also be useful in case you want to write portable code. Other compilers might not understand __attribute__
and trip over it. Defining the macro empty for other compilers can help writing portable code.
You can read more about __attribute__
in Using the GNU Compiler Collection (GCC) and the Clang Compiler User's Manual.
3.2.4 Combined approach for Multiple Language Versions and Compilers
The previous approaches can be combined to support multiple compilers. It should be easy to extend for compilers that use a syntax not mentioned here, like __declspec
.
3.3 Suppressing Warnings by Controlling the Diagnostic Stack
GCC and Clang have a diagnostic stack which contains the configuration for diagnostics. Which warnings and errors to show is part of that configuration. It is possible to save the diagnostics configuration state, change it, and then restore it. That it's a stack means that this can be nested. The diagnostic stack is controlled with pragmas. The C language supports two types of pragmas:
#pragma
directive_Pragma()
operator
They both work pretty much the same way, just the syntax of how to get it into the C file is different. The expression-like _Pragma()
is newer, it was introduced in C99.
3.3.1 #pragma
Directive
You might wonder if you need to replace GCC
with clang
in case you use Clang instead of GCC. No, you needn't. Clang understands these GCC pragmas just fine. You could replace clang
with GCC
. But clang
only works for Clang, and GCC
works for both, GCC and Clang.
3.3.2 _Pragma()
Operator
The _Pragma()
operator was added to the C standard for version C99 (ISO/IEC 9899:1999). Because it is an operator, it can be used in macros.
3.3.3 _Pragma()
Operator with Macro
3.4 Suppressing per file in the Makefile
You can also suppress warnings in the Makefile
. This can be done on a per-file basis. More generally speaking, you can alter variables on a per-file basis. The variable CPPFLAGS
controls the command-line options for the C preprocessor and compiler.
4 Comparison of Approaches
We've seen different approaches to addressing compiler warnings. Let's recap and summarize.
The best approach, if you have tests, is to refactor the code to be even better and not have warnings. If you do not have tests, be aware of the risks of that approach. The second-best approach is to give the compiler more information.
Writing Different Code | Give the compiler more info | Actually suppress | ||||||
---|---|---|---|---|---|---|---|---|
specifiers like _Noreturn | standard attributes [[ ]] | __attribute__ | _Pragma | #pragma | Command Line | |||
Macro capable | n/a | ☑ | ☑ | ☑ | ☑ | ☐ | ☐ | |
Scope | warning | declaration | lines | file | ||||
Risk | Tests | low | low | low | low | medium | medium | high |
No Tests | high | |||||||
Since | always | depends on specifier | C2x / depends on attribute | implementation defined | C99 / implementation defined | C90 / implementation defined | implementation defined |
4.1 Source on GitHub
The source code of all examples is available on GitHub.