Florian Weimer
> + Function prototyping was added, first to help enforce type checking > + on both the types of the arguments passed to the function, and also > + to check the assignment compatibility of the function return type. > + > +> + > +The initial ISO C standard and its 1999 revision removed support for > +many C language features that were widely known as sources of > +application bugs due to accidental misuse. For backwards > +compatibility, GCC 13 and earlier compiler versions diagnosed use of > +these features as warnings only. Although these warnings have been > +enabled by default for many releases, experience shows that these > +warnings are easily ignored, resulting in difficult-to-diagnose bugs. > +In GCC 14, these issues are now reported as errors, and no output file > +is created, providing clearer feedback to programmers that something > +is wrong. > + > +
> +Most components of the GNU project have already been fixed for > +compatibility, but not all of them have had releases since fixes were > +applied. Programs that bundle parts > +of gnulib or > +autoconf-archive > +may need to update these sources files from their upstream versions. > + > +
> +Several GNU/Linux distributions have shared patches from their porting > +efforts on relevant upstream mailing lists and bug trackers, but of > +course there is a strong overlap between programs that have these > +historic C compatibility issues and are dormant today. > + > +
int
types (-Werror=implicit-int
)int
keyword
> +addresses the error. For example, a flag like
> +
> +> + static initialized; > +> + > +might turn into: > + > +
> + static int initialized; > +> + > +
If the return type of a function is omitted, the correct type to
> +add could be int
or void
, depending on
> +whether the function returns a value or not.
> +
> +
In some cases, the previously implied int
type
> +was not correct. This mostly happens in function definitions
> +that are not prototypes, when argument types are not
> +declared outside the parameter list. Using the correct
> +type maybe required to avoid int-conversion errors (see below).
maybe -> may be
> +In the example below, the type of s
should be
> +const char *
, not int
:
> +
> +
> + write_string (fd, s) > + { > + write (1, s, strlen (s)); > + } > +> + > +The corrected standard C source code might look like this (still > +disregarding error handling and short writes): > + > +
> + void > + write_string (int fd, const char *s) > + { > + write (1, s, strlen (s)); > + } > +> + > +
-Werror=implicit-function-declaration
)
> +For well-known functions declared in standard headers, GCC provides
> +fix-it hints with the appropriate #include
directives:
> +
> +
> +error: implicit declaration of function ‘strlen’ [-Wimplicit-function-declaration] > + 5 | return strlen (s); > + | ^~~~~~ > +note: include ‘<string.h>’ or provide a declaration of ‘strlen’ > + +++ |+#include <string.h> > + 1 | > +> + > +
> +On GNU systems, headers described in standards (such as the C > +standard, or POSIX) may require the definition of certain > +macros at the start of the compilation before all required > +function declarations are made available. > +See Feature Test Macros > +in the GNU C Library manual for details. > + > +
> +Some programs are built with -std=c11
or
> +similar -std
options that do not contain the
> +string gnu
, but these programs still use POSIX or other
> +extensions in standard C headers such as <stdio.h>
.
> +The GNU C library automatically suppresses these extensions in
> +standard C mode, which can result in implicit function declarations.
> +To address this, the -std=c11
option can be
> +dropped, -std=gnu11
can be used instead,
> +or -std=c11 -D_DEFAULT_SOURCE
can be used re-enable
> +common extensions.
It's fine if you leave this out, but consider mentioning the common
pitfall of autoconf projects not including config.h consistently before
all inclues. We could also mention AC_USE_SYSTEM_EXTENSIONS.
Both are weak suggestions and I don't mind if you don't apply them.
> +
> +
> +If undeclared functions from the same project are called and there is
> +yet no suitable shared header file, you should add a declaration to a
> +header file that is included by both the callers and the source file
> +containing the function definition. This ensures that GCC checks that
> +the prototype matches the function definition. GCC can perform type
> +checks across translation units when building with options such as
> +-flto -Werror=lto-type-mismatch
, which can help with
> +adding appropriate prototypes.
> +
> +
> +In some rare cases, adding a prototype may change ABI in inappropriate > +ways. In these situations, it is necessary to declaration a function > +without prototype: > + > +
> + void no_prototype (); > +> + > +However, this is an obsolete C feature that will change meaning in C23 > +(declaration a function with a prototype and accepting no arguments, > +similar to C++). Usually, a prototype with the default argument > +promotions applied can be used instead. > + > +
> +When building library code on GNU systems, it was possible to call > +undefined (not just undeclared) functions and still run other code in > +the library, particularly if ELF lazy binding was used. Only > +executing the undefined function call would result in a lazy binding > +error and program crash. Maybe explicitly refer to the bfd linker's relaxed behaviour so it sounds less mysterious. > + > +
-Werror=declaration-missing-parameter-type
)-Wdeclaration-missing-parameter-type
warning. The
> +second line in the following example is now treated as an error
> +(previously this resulted in an unnamed warning):
> +
> +> + typedef int *int_array; > + int first_element (intarray); > +> + > +The fix is to correct the spelling mistake: > + > +
> + typedef int *int_array; > + int first_element (int_array); > +> + > +GCC will type-check function arguments after that, potentially > +requiring further changes. (Previously, the function declaration was > +treated as not having no prototype.) > + > +
return
statement (-Werror=return-mismatch
)return
statements with expressions
> +in functions which are declared to return void
, or
> +return
statements without expressions for functions
> +returning a nonvoid
type.
> +
> +
> +To address this, remove the incorrect expression (or turn it into a
> +statement expression immediately prior to the return
> +statements if the expression has side effects), or add a dummy return
> +value, as appropriate. If there is no suitable dummy return value,
> +further changes may be needed to implement appropriate error handling.
> +
> +
> +Previously, these mismatches were diagnosed as
> +a -Wreturn-type
warning. This warning still exists, and
> +is not treated as an error by default. It now covers remaining
> +potential correctness issues, such as reaching the closing
> +brace }
of function that does not
> +return void
.
> +
> +
> +By default, GCC still accepts returning an expression of
> +type void
from within a function that itself
> +returns void
, as a GNU extension that matches C++ rules
> +in this area.
> +
> +
-Werror=int-conversion
)
> +It makes sense to address missing int
type, implicit
> +function declarations, and incorrect return
statement
> +usage prior to tackling these int
-conversion issues.
> +Some of them will be caused by missing types resulting
> +in int
, and the default int
return type of
> +implicitly declared functions.
> +
> +
To fix the remaining int
-conversions issues, add casts
> +to an appropriate pointer or integer type. On GNU systems, the
> +standard (but generally optional) types
> +intptr_t
and uintptr_t
(defined
> +in <stdint.h>
) are always large enough to store all
> +pointer values. If you need a generic pointer type, consider
> +using void *
.
> +
> +
Note that in some cases, it may be more appropriate to pass the > +address of an integer variable instead of a cast of the variable's > +value. > + > +
-Werror=incompatible-pointer-types
)void *
type and
> +its qualified variations.
> +
> +
> +To fix the compilation errors resulting from that, you can add the
> +appropriate casts, and maybe consider using code void *
> +in more places (particularly for old programs that predate the
> +introduction of void
into the C language).
> +
> +
> +Programs that do not carefully track pointer types are likely to
> +contain aliasing violations, so consider building
> +with -fno-strict-aliasing
as well. (Whether the casts
> +are written manually or performed by GCC automatically does not make a
> +difference in terms of strict aliasing violations.)
> +
Thanks for calling that out specifically.
> +
> +A frequent source of incompatible function pointer types involves > +callback functions that have more specific argument types (or less > +specific return types) than the function pointer they are assigned to. > +For example, old code which attempts to sort an array of strings might > +look like this: > + > +
> +#include <stddef.h> > +#include <stdlib.h> > +#include <string.h> > + > +int > +compare (char **a, char **b) > +{ > + return strcmp (*a, *b); > +} > + > +void > +sort (char **array, size_t length) > +{ > + qsort (array, length, sizeof (*array), compare); > +} > +> + > +To correct this, the callback function should be defined with the > +correct type, and the arguments should be cast as appropriate before > +they are used (as calling a function through a function pointer of an > +incorrect type is undefined): > + > +
> +int > +compare (const void *a1, const void *b1) > +{ > + char *const *a = a1; > + char *const *b = b1; > + return strcmp (*a, *b); > +} > +> + > +
> +A similar issue can arise with object pointer types. Consider a
> +function that is declared with an argument of type
> +void **
, and you want to pass the address of a variable
> +of type int *
:
> +
> +
> +extern int *pointer; > +extern void operate (int command, void **); > + > +operate (0, &pointer); > +> + > +In these cases, it may be appropriate to make a copy of the pointer > +with the correct
void *
type:
> +
> +> +extern int *pointer; > +extern void operate (int command, void **); > + > +void *pointer1 = pointer; > +operate (0, &pointer1); > +pointer = pointer1; > +> + > +As mentioned initially, adding the cast here would not eliminate any > +strict aliasing violation in the implementation of > +the
operate
function. Of course in general, introducing
> +such additional copies may alter program behavior.
> +
> +
> +Some programming styles rely on implicit casts between related object
> +pointer types to implement C++-style struct
inheritance.
> +It may be possible to avoid writing manual casts with
> +the -fplan9-extensions
options and unnamed
> +initial struct
fields for the base type in
> +derived struct
s.
> +
> +
> +Some programs use a concrete function pointer type such as
> +void (*) (void)
as a generic function pointer type
> +(similar to void *
for object pointer types), and rely on
> +implicit casts to and from this type. The reason for that is that C
> +does not offer a generic function pointer type, and standard C
> +disallows casts between function pointer types and object pointer
> +types. On most targets, GCC supports implicit conversion
> +between void *
and function pointer types. However, for
> +a portable solution, the concrete function pointer type needs to be
> +used, together with explicit casts.
> +
> +
> +In cases where this is a concern, generated config.log
,
> +config.h
and other source code files can be compared
> +using diff,
> +to ensure there are no unexpected differences.
> +
> +
> +This phenomenon also impacts similar procedures part of CMake, Meson, > +and various build tools for C extension modules of scripting > +languages. > + > +
> +Autoconf has supported C99 compilers since at least version 2.69 in > +its generic, core probes. (Specific functionality probes may have > +issues addressed in more recent versions.) Versions before 2.69 may > +have generic probes (for example for standard C support) that rely on > +C features that were removed in 1999 and thus fail with GCC 14. > + > +
> +Sources that cannot be ported to standard C can be compiled
> +with -fpermissive
, -std=gnu89
,
> +or -std=c89
. Despite their names, the latter two options
> +turn on support for pre-standard C constructs, too. With the
> +-fpermissive
options, programs can use C99 inlining
> +semantics and features that were removed from C99. Alternatively,
> +individual warnings can be downgraded to warnings using
> +the -Wno-error=…
option, or disabled complete
> +with -Wno-…
. For example,
> +-Wno-error=incompatible-pointer-types
turns off most type
> +checking for pointer assignments.
> +
> +
> +Some build systems do not pass the CFLAGS
environment
> +or make
variable to all parts of the builds, and may
> +require setting CC
to something like gcc
> +-fpermissive
instead. If the build system does not support
> +whitespace in the CC
variable, a wrapper script like this
> +may be required:
> +
> +
> +#!/bin/sh > +exec /usr/bin/gcc -fpermissive "$@" > +> + > +
#pragma GCC diagnostic warning
directives to
> +turn these errors back into warnings:
> +
> +> +#if defined __GNUC__ && __GNUC__ >= 14 > +#pragma GCC diagnostic warning "-Wimplicit-function-declaration" > +#pragma GCC diagnostic warning "-Wincompatible-pointer-types" > +#pragma GCC diagnostic warning "-Wint-conversion" > +#pragma GCC diagnostic warning "-Wreturn-mismatch" > +#endif > +> + > +Not listed here are
-Wimplicit-int
> +and -Wdeclaration-missing-parameter-type
because they
> +should be straightforward to address in a code generator.
> +
> +
> +It is unclear at which point GCC can enable the C23 bool
> +keyword by default (making the bool
type available
> +without including #include <stdbool.h>
explicitly).
> +Many programs define their own bool
types, sometimes with
> +a different size of the already-available _Bool
type. A
> +further complication is that even if the sizes are the same, a custom
> +bool
typically does not have trap representations,
> +while _Bool
and the new bool
type do. This
> +means that there can be subtle compatibility issues, particularly when
> +processing untrusted, not necessarily well-formed input data.
> +
> +
> +GCC is unlikely to warn about function declarations that are not > +prototypes by default. This means that there is no stringent reason > +to turn > + > +
> +void do_something (); > +> + > +into > + > +
> +void do_something (void); > +> + > +except for diagnosing extraneous ignored arguments as errors. A > +future version of GCC will likely warn about calls to functions > +without a prototype which specify such extraneous arguments > +(
do_something (1)
, for example). Eventually, GCC will
> +diagnose such calls as errors because they are constraint violations
> +in C23.
> +
> +> +GCC will probably continue to support old-style function definitions > +even once C23 is used as the default language dialect. > + >