Does changing the target C standard achieve anything? - c

I'm interested in the effects of compiling valid C99 code with a C11 compiler. Is there any practical difference?
As an example, could changing
gcc -c -pedantic -std=c99 source.c
to
gcc -c -pedantic -std=c11 source.c
achieve anything, where source.c is valid C99? Could this introduce regressions, or give optimisations for free?
I'm interested specifically in gcc, although answers addressing other compilers are most welcome.
I used the C11 Wikipedia page as a quick check to see the difference between C99 and C11.
I do notice that gets is removed in C11, so that's one possible regression. The only other one I can see is if the code does something like version detection that's not future-proof, like #if __STDC_VERSION__ == 199901L .

Backwards compatibility is considered very important for the committee that maintains the C standard.
You can expect that a strictly conforming program written according to the preceding standard will function identically when compiled with the settings for the new standard, unless
the program uses a feature that was removed (gets when moving from C99 to C11)
the program uses a feature that was made optional and is not provided by the compiler (e.g. complex types or VLA's)
The latter is unlikely to really hit you, because it is not expected that compilers that had these features will remove them now they are optional. It is more likely that if a compiler in C11 mode doesn't support VLA's, then it also doesn't do so in C99 mode (and will be non-conforming to C99 in that respect).
For programs that aren't strictly conforming (the majority of real programs), you also have to check that the new additions don't interfere with your code. Things to watch out for are:
New standard headers that have the same name as your own headers
Incorrect use of reserved identifiers that have been given a use in the new standard. In particular, identifiers that start with an underscore and a capital letter

Related

How can I specify to gcc that {} init in C shouldn't compile?

with gcc using -std=gnu99, the following code compiles:
void f()
{
struct X data = {};
// do something with data
}
Is this valid C ?
Is this a gnu extension ?
How can I tell gcc to not accept this kind of init ?
I want to ensure compatibility with other compilers (like visual 2015 for example)
If you want to reject code containing GNU-specific extensions, use -std=c99 -pedantic-errors (-pedantic will issue diagnostics for non-standard extensions, but it won't necessarily reject the code outright). However, if you want to guarantee ISO conformance, be aware that this isn't a 100% solution. From the gcc man page:
Some users try to use -pedantic to check programs for strict ISO C conformance. They soon find that it does not do quite what they want: it finds some non-ISO practices, but not all---only those for which ISO C requires a diagnostic, and some others for which diagnostics have been added.
A feature to report any failure to conform to ISO C might be useful in some instances, but would require considerable additional work and would be quite different from -pedantic. We don't have plans to support such a feature in the near future.
The -pedantic option will cause a warning to be displayed in this case, and -Werror will cause all warnings to be treated as errors.
For example:
x1.c: In function ‘f’:
x1.c:11:19: error: ISO C forbids empty initializer braces [-Werror=pedantic]
struct X data = {};
No, the empty initializer is not standard C. It is a gcc extension. See this for a detailed description.
By specifying -std=gnu99, you allowed the GNU extensions to be used. You can force the compiler to only allow the standard conforming code, by specifying -std=cXX option.
From the gcc online manual (emphasis mine)
-std=
The compiler can accept several base standards, such as ‘c90’ or ‘c++98’, and GNU dialects of those standards, such as ‘gnu90’ or ‘gnu++98’. When a base standard is specified, the compiler accepts all programs following that standard plus those using GNU extensions that do not contradict it. For example, -std=c90 turns off certain features of GCC that are incompatible with ISO C90, such as the asm and typeof keywords, but not other GNU extensions that do not have a meaning in ISO C90, such as omitting the middle term of a ?: expression. On the other hand, when a GNU dialect of a standard is specified, all features supported by the compiler are enabled, even when those features change the meaning of the base standard. As a result, some strict-conforming programs may be rejected. The particular standard is used by -Wpedantic to identify which features are GNU extensions given that version of the standard. For example -std=gnu90 -Wpedantic warns about C++ style ‘//’ comments, while -std=gnu99 -Wpedantic does not.

What is the difference between the "c99" and "gcc" commands with appropriate flags?

Up until today I always read on the Internet how gcc is the best compiler for C (at least for the student level of programing, followed closely by Clang).
However in "21st Century C" Mr Ben Klemens suggests that c99 is better(?) than running gcc -std=c99 (actual line is [page 11]: everybody else switched to C99 being the default a long
time ago...)
I wasn't able to find anything on the subject of c99 compiler, so my question is:
Is there any difference between those commands and if there are, which one is better?
EDIT: The standard C99 is clearly metioned in the paragraph, however from the beginning the suggested method of compiling is the command:
gcc erf.c -o erf -lm -g -Wall -O3 -std=gnu11
However on page 11 the author states:
The POSIX standard specifies that c99 be present on your system, so the
compiler-agnostic version of the above line would be:
c99 erf.c -o erf -lm -g -Wall -O3
This seems to suggest there is a difference in those 2 commands. I wasn't able to find any additional info nor was it clear to me from the text, what the second line is exactly (no man page for c99 on my Cygwin either).
C99 is the 1999 edition of the ISO C standard. It replaced the 1990 standard, and has been (officially, at least) replaced by the 2011 standard.
What you're asking about, though, is the c99 command (I've updated your question's title to clarify that).
POSIX specifies a c99 command. The requirements are documented here. It is "an interface to the standard C compilation system".
On typical Linux systems, the c99 command /usr/bin/c99 is a small shell script that invokes the gcc commmand. It invokes gcc with the -std=c99 option. It also checks whether the user has already specified an equivalent option, so it doesn't use the same option twice. If an incompatible option has been given, such as c99 -std=c90, it terminates with an error message.
Given such an implementation, the command
c99 [args]
is exactly equivalent to
gcc -std=c99 [args]
As I mentioned above, the C99 standard has been officially superseded by the C11 standard. gcc version 5 (the current latest release is 5.3.1) has reasonably good support but not 100% complete support for C11. POSIX has not (yet) specified a c11 command.
There's nothing wrong with using the C99 standard if you don't need C11-specific features -- or even the C90 standard if you don't need C99-specific features.
In my PDF copy of the book, the discussion about using c99 instead of gcc -std=c99 seems to be on page 10, not 11.
And what is being discussed is not that c99 is "better" than gcc, but that you might be able to more easily use C99-standard compiler features with the c99 command, since you don't then need to know the specific option to enable C99 features or whether the default for the compiler is C99 or C89.
On my system, the command c99 is just an alias or link for gcc that has the -std=c99 set by default (and complains if a non-C99 standard is specified with the -std= option). I imagine that or something similar is true on most systems with a c99 compiler command.
In fact, on my system c99 is a link to a shell script:
#! /bin/sh
# Call the appropriate C compiler with options to accept ANSI/ISO C
# The following options are the same (as of gcc-3.3):
# -std=c99
# -std=c9x
# -std=iso9899:1999
# -std=iso9899:199x
extra_flag=-std=c99
for i; do
case "$i" in
-std=c9[9x]|-std=iso9899:199[9x])
extra_flag=
;;
-std=*|-ansi)
echo >&2 "`basename $0` called with non ISO C99 option $i"
exit 1
;;
esac
done
exec gcc $extra_flag ${1+"$#"}
Try c99 --version on a typical Linux box. You will get the version and name of the compiler which is gcc.
c99 is just a shortcut to the c99 compliant compiler on your machine. That way you don't have to care about the actual compiler used. POSIX also requires some common command line options the compiler has to understand. If that is gcc, it shall enable c99 compliant features. This should be identical to gcc -std=c99.
gcc provides additional features which are enabled by default [1] when called by its native name and by the -std=gccXX option in addition to the CXX standard. For older versions, some of these extensions became part of the next C standard either directly or with slightly different syntax. A typical and appreciated extension for C90 is support for C++-style line-comments:
// this is not allowed in pure C90
For c99/gnu99 things are less obvious, but might still add some usefull features.
On other POSIX systems, e.g. Unix, you may find a different compiler. It shall still be available by the name c99.
Note that the current and only valid C standard is C11 since 2011. So if you want to use the new features (e.g. atomics, thread-support), you have to deviate from the pure POSIX-path. Yet it is likely POSIX might be updated some day.
[1] The default version of the C standard depends on the version of gcc. pre5 used C90, while gcc 5.x uses C11.

GCC options for strict C90 code?

I am trying to find what is the combination of gcc flags to use when testing strict C90 conformance. According to previous post: GCC options for strictest C code?, I should only need a --std=c90.
However here is what I tried:
$ cat t.c
#include <stdint.h> /* added in C99 */
int main()
{
uint64_t t;
return 0;
}
$ gcc -std=c90 -ansi -pedantic t.c
The above does work well (no warnings/errors produced).
Does anyone knows of:
gcc flags to have strict ISO/IEC 9899:1990 conformance
A different compiler (tcc, clang...) with different set of flags ?
EDIT:
Sorry for my wording, yes I would really like to mimic a strictly conforming C90 compiler, in other word it should fail if the code tries to use any feature added later (C99 comes to mind). So pthread include header ought to emit a warning when compiled in what GNU/GCC calls C90 mode (just like stdint.h header should produce a warning without C99). -pedantic nicely warns me about usage of long long, I do not see why it should not warn me about uint64_t.
I used the terminology of ISO/IEC 9899:1990 as quoted from:
http://en.wikipedia.org/wiki/C_(programming_language)#ANSI_C_and_ISO_C
In 1990, the ANSI C standard (with formatting changes) was adopted by
the International Organization for Standardization (ISO) as ISO/IEC
9899:1990, which is sometimes called C90. Therefore, the terms "C89"
and "C90" refer to the same programming language.
EDIT2:
GCC documentation are actually quite clear:
Some features that are part of the C99 standard are accepted as
extensions in C90 mode, and some features that are part of the C11
standard are accepted as extensions in C90 and C99 modes.
So my question is rephrased into:
Is there a compiler + standard include header on a linux system which strictly conforms to C90 ?
C90 compliance doesn't mean that the compiler can't offer other headers that aren't mentioned in the C90 standard. (sys/socket.h, for instance.) If you want to disallow these for some strange reason, you can pass the -I option to add an extra include path, and in that path put versions of all the C99-only headers which are simply #error Don't include me.
Keep in mind here that GCC itself is a conforming freestanding implementation of the C standard specified; such an implementation only supplies a small subset of the standard header files, and practically none of the actual functionality of the C standard library, instead relying on another party -- glibc on Linux systems, for instance -- to supply the C standard library's functionality.
What you seek is something that not only warns you when you are using a C99/C11/GNU language feature that is not in C90, but when you use a library function that is not defined by C90 itself. Sadly, the compiler alone cannot do this for the reason stated above -- it is aloof to what libc it is used with. On glibc systems, the C standard library will pick up on the macros defined by -std=c90 or -ansi:
The macro __STRICT_ANSI__ is predefined when the -ansi option is used. Some header files may notice this macro and refrain from declaring certain functions or defining certain macros that the ISO standard doesn't call for; this is to avoid interfering with any programs that might use these names for other things.
and give you some help by turning off gratuitous extensions:
If you compile your programs using ‘gcc -ansi’, you get only the ISO C library features, unless you explicitly request additional features by defining one or more of the feature macros.
However, this only covers extensions and POSIX-but-not-ISO C functions; it will not save you if a function's behavior is specified differently in ISO C and POSIX.1!

How do I check by using __STDC_VERSION__ if is -std=c1x in use?

I know that for C11, I can test #if(__STDC_VERSION >= 20112L). But for -std=c1x
what macro and/or value should I test it?
what's the nomenclature of this standard? or maybe a informal name, if any.
I hope this is clear. Thanks in advance.
gcc's -std=c1x option is synonymous with -std=c11, and it sets __STDC_VERSION__ to the same value, 201112L (note: not 20112L).
Before it was released, the new C standard was referred to as "C1X" (since it wasn't known exactly when it would come out), and gcc added a -std=c1x option to enable partial support for the upcoming standard. When the standard was released as C11, gcc added -std=c11 to enable (still partial) support, but has kept the -std=c1x option for compatibility.
(Due to an editing error, the released 2011 ISO C standard doesn't specify the value of __STDC_VERSION__, but the editor has stated that 201112L is correct; see this question.)
Jens Gustedt's comment makes a good point. gcc -std=c11 sets __STDC_VERSION__ to 201112LL, which is supposed to imply C11 conformance, but in fact it's still missing a log of C11 features. We can expect this to improve in future releases.
Similarly, -std=c99 sets __STDC_VERSION__ to 199901L, but it doesn't quite conform to the C99 standard (the current status is documented here. gcc's C90 conformance (with -ansi or -std=c90) conforms quite well to the C90 standard.

Should I use "-ansi" or explicit "-std=..." as compiler flags?

I've read that ANSI C is not exactly the same as ISO C and compilers may differ in interpretation of what "-ansi" is about. (gcc maps it to C90, clang maps it to C89) At the moment I would tend to use "-std=..." over "-ansi" as then it is explicitly shown which standard is used. As I am specifically interested in compiling on Linux, Windows and MAC, I fear some compilers could not understand "-std=..." but "-ansi". So are there any pros and cons for using the one over the other?
If you want the compiler to enforce the 1989 ANSI C standard, or equivalently the 1990 ISO C standard (they describe exactly the same language), you can safely use either -ansi or -std=c89.
The name -ansi is, strictly speaking, incorrect; it refers to the 1989 ANSI C standard, but ANSI itself considers that standard to be obsolete; it was replaced by the 1999 ISO C standard (which ANSI officially adopted shortly after it was released) which itself either has been, or soon will be, replaced by the new 2011 ISO C standard. But changing the meaning of the -ansi option would break too many Makefiles and build scripts.
The gcc 4.7 and later versions also recognize -std=c90 as a synonym for -std=c89. gcc 4.7 was released in March 2012, so -std=c90 is reasonably portable unless you need to allow for older versions of gcc.
-std=c99 enforces (most of) the 1999 ISO C standard. Since Microsoft in particular doesn't support C99 (even after all these years), using this option means the compiler won't warn you about use of C99-specific features that might not be supported elsewhere. gcc's C99 support is documented here.
gcc 4.7 has partial support for the new ISO C 2011 standard, with -std=c11. That support has improved in later releases, but is not yet complete. gcc C11 status is documented here, and is said to be similar to the level of C99 support.
There are more options, and a number of aliases for the ones I've mentioned; for example, the option -std=c9x was added before the 1999 ISO standard was finalized, and it's still supported; similarly, -std=c1x is a synonym for -std=c11.
I believe that clang is intended to be as compatible as possible with gcc, so it should support the same options with the same meanings (except perhaps for some of the newer ones, depending on which versions of gcc and clang you're using).
The gcc manual has the full details, with one section describing the supported standards and another specifying the various -ansi and -std=... options. The links are to the 4.7 version. You can also run info gcc (if you have the GNU info command and the gcc documentation installed), or you can see multiple versions of the manual here.
If you're going to use compilers other than gcc (and compilers that aim to be gcc-compatible), you'll have to read their documentation to find out how to enforce various versions of the C standard.
-ansi and -std= compiler flags may be shared by other compilers but they are gcc flags.
As of now -ansi is equivalent to -std=c89 in gcc but this may1) change in the future so I suggest you to use -std=c89 over -ansi. Indeed ISO c99 for example has also been ratified by ANSI.
You should note that c89 and c90 are essentially the same C Standard. c89 is the ANSI name while c90 is the ISO name.
From gcc page:
There were no technical differences between these publications, although the sections of the ANSI standard were renumbered and became clauses in the ISO standard. This standard, in both its forms, is commonly known as C89, or occasionally as C90, from the dates of ratification.
1) As noted by Keith Thompson in the comments, even though it's probably unlikely as it would break many build scripts.

Resources