Porting to GCC 5
The GCC 5 release series differs from previous GCC releases ina number of ways. Some of these are a result of bug fixing, and some old behaviors have been intentionally changed in order to support new standards, or relaxed in standards-conforming ways to facilitate compilation or run-time performance. Some of these changes are not visible to the naked eye and will not cause problems when updating from older versions.
However, some of these changes are visible, and can cause grief to users porting to GCC 5. This document is an effort to identify major issues and provide clear solutions in a quick and easily searched manner. Additions and suggestions for improvement are welcome.
Preprocessor issues
The preprocessor started to emit line markers to properly distinguish whether a macro token comes from a system header, or from a normal header (see PR60723). These new markers can cause intriguing problems for software not ready to handle them. To stop the preprocessor from generating the #line
directives, usethe -P option.
Consider the following snippet:
#include <stdlib.h>
exitfailure EXIT_FAILURE
In the past "gcc -E
" used to emit:
# 2 "t.c" 2
exitfailure 1
Current GCC emits:
# 2 "t.c"
exitfailure
# 2 "t.c" 3 4
1
Observe how the exitfailure
and 1
tokens are not on the same line anymore.
C language issues
Default standard is now GNU11
GCC defaults to -std=gnu11
instead of -std=gnu89
. This brings several changes that users should be aware of. The following paragraphs describe some of these changes and suggest how to deal with them.
Some users might prefer to stay with gnu89, in which case we suggest to use the -std=gnu89
command-line option, perhaps by putting it in override CFLAGS
or similarly in Makefiles.
To ease the migration process, GCC offers two new warning options,-Wc90-c99-compat
and -Wc99-c11-compat
. The former warns about features not present in ISO C90, but present in ISO C99. The latter warns about features not present in ISO C99, but present in ISO C11. See the GCC manual for more info.
Different semantics for inline functions
While -std=gnu89
employs the GNU89 inline semantics,-std=gnu11
uses the C99 inline semantics. The C99 inline semantics requires that if a function with external linkage is declared withinline
function specifier, it also has to be defined in the same translation unit (TU). Consequently, GCC now warns if it sees a TU such as the following:
inline int foo (void);
This example now gives the following diagnostic:
f.c:1:12: warning: inline function 'foo' declared but never defined inline int foo (void); ^
Furthermore, there is a difference between extern inline
andinline
:
- C99
inline
: No externally visible function is generated. If the function is referenced in this TU, an external definition has to exist in another TU; same as GNU89extern inline
with no redefinition. - C99
extern inline
: An externally visible function is generated; same as GNU89inline
. - GNU89
inline
: Same as C99extern inline
. - GNU89
extern inline
: No externally visible function is generated; no equivalent in C99, because redefinition is not permitted. (Fortunatelystatic inline
is the same in both C99 and GNU89.)
In other words, ISO C99 requires that exactly one C source file has the callable copy of the inline function. Consider the following program:
inline int
foo (void)
{
return 42;
}
int
main (void)
{
return foo ();
}
The program above will not link with the C99 inline semantics, because no out-of-line function foo
is generated. To fix this, either mark the function foo
as extern
, or add the following declaration:
extern inline int foo (void);
This ensures that an externally visible function be emitted. To enforce the GNU89 inline semantics, you can either use the-fgnu89-inline
command-line option, or mark a function with thegnu_inline
attribute. For example:
__attribute__ ((gnu_inline)) inline int
foo (void)
{
return 42;
}
A program which used GNU89 extern inline
may fail in the new standard due to multiple definition errors:
extern inline int
foo (void)
{
return 42;
}
int
foo (void)
{
return 23;
}
int
main (void)
{
return foo ();
}
Some warnings are enabled by default
The C99 mode enables some warnings by default. For instance, GCC warns about missing declarations of functions:
int
foo (void)
{
return bar ();
}
This example now gives the following diagnostic:
w.c:4:10: warning: implicit declaration of function 'bar' [-Wimplicit-function-declaration] return bar (); ^
To suppress this warning add the proper declaration:
int bar (void);
or use -Wno-implicit-function-declaration
.
Another warning that is now turned on by default is the warning about implicit int, as in the following snippet:
foo (u)
{
return u;
}
This example now gives the following diagnostic:
q.c:1:1: warning: return type defaults to 'int' [-Wimplicit-int] foo (u) ^ q.c: In function 'foo': q.c:1:1: warning: type of 'u' defaults to 'int' [-Wimplicit-int]
To suppress this warning just add the proper types:
int
foo (int u)
{
return u;
}
or use -Wno-implicit
or -Wno-implicit-int
.
Another warning that is now turned on by default is the warning about returning no value in a function returning non-void:
int
foo (void)
{
return;
}
This example now gives the following diagnostic:
q.c:4:3: warning: 'return' with no value, in function returning non-void return; ^
The fix is either to specify a proper return value, or to declare the return type of foo
as void
.
Initializing statics with compound literals
Previously, initializing objects with static storage duration with compound literals was only allowed in the GNU89 mode. This restriction has been lifted and currently it is possible to do this even in C99/C11 mode. The following snippet is an example of such initialization:
struct T { int i; };
struct S { struct T t; };
static struct S s = (struct S) { .t = { 42 } };
We used to reject such code in C99/C11 mode:
q.c:3:29: error: initializer element is not constant static struct S s = (struct S) { .t = { 42 } }; ^
Note that using -Wpedantic
will cause a warning be emitted:
q.c:3:29: warning: initializer element is not constant [-Wpedantic] static struct S s = (struct S) { .t = { 42 } }; ^
__STDC_VERSION__ macro
As the default mode changed to C11, the __STDC_VERSION__
standard macro, introduced in C95, is now defined by default, and has the value 201112L
.
Typically, this macro is used as in the following:
#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
/* ... */
#else
# include <stdint.h>
#endif
You can check the macro using gcc -dM -E -std=gnu11 - < /dev/null | grep STDC_VER
.
Different meaning of the %a *scanf conversion specification
In C89, the GNU C library supports dynamic allocation via the %as
,%aS
, and %a[...]
conversion specifications; seethis for more info. In C99, the a
conversion specifier is a synonym for f
(float), so the compiler expects an argument of type float *
. This is a change in semantics, and in combination with the-Wformat
warning option the compiler may emit additional warnings:
#include <stdio.h>
int
main (void)
{
char *s;
scanf ("%as", &s);
}
q.c:7:10: warning: format '%a' expects argument of type **'float *'**, but argument 2 has type 'char ' [-Wformat=] scanf ("%as", &s); ^
To use the dynamic allocation conversion specifier in C99 and C11, specifym
as a length modifier as per POSIX.1-2008. That is, use%ms
or %m[...]
.
New warnings
Several new warnings have been added to the C front end. Among others-Wpedantic
now warns about non-standard predefined identifiers. For instance:
void
foo (void)
{
const char *s = __FUNCTION__;
}
q.c:4:19: warning: ISO C does not support 'FUNCTION' predefined identifier [-Wpedantic] const char *s = FUNCTION; ^
The fix is either to use the standard predefined identifier __func__
(since C99), or to use the __extension__
keyword:
const char *s = __extension__ __FUNCTION__;
C++ language issues
Converting std::nullptr_t to bool
Converting std::nullptr_t
to bool
in C++11 mode now requires direct-initialization. This has been changed inDR 1423.
As a consequence, the following is invalid:
bool b = nullptr;
but the following is valid:
bool b(nullptr);
It is recommended to use the false
keyword instead of converting nullptr
to bool
.
Return by converting move constructor
GCC 5 implementsDR 1579which means that when compiling a function like:
X
foo()
{
Y y;
return y;
}
GCC first attempts to construct the return value as though y
were an rvalue, and if that fails then it tries again using an lvalue (all C++11 compilers already do this when returning a variable of the same type as the function returns, but now they are also required to do it when the types are not the same). This changes the constructor that gets called in some cases, for example it might now call X(Y&&)
instead ofX(const Y&)
.
In most cases the only observable difference is code that runs faster (by moving instead of copying) but if it causes a problem the new behavior can be prevented by ensuring the compiler treats y
as an lvalue, using return X(y);
orreturn static_cast<Y&>(y);
.
Links
Marek Polacek and Jakub Jelinek,Fedora test rebuild on x86_64-linux-gnu with gcc-5.0.0-0.5.fc22