GCC options for strict C90 code? - c

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!

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.

How can some GCC compilers modify a constant char pointer?

I am reading a book titled "Understanding and Using C pointers".
On page 110, it had these lines:
... However, in some compilers, such as GCC, modification of the string literal is possible. Consider the following example:
char *tabheader = "Sound";
*tabheader = 'L';
printf("%s\n", tabheader); //Displays "Lound"
It goes on and describe the usage of const char *tabheader which will prevent from modifying this variable.
I am currently using Cloud 9/Ubuntu. I compiled this code using GCC and ran it. It caused segmentation fault error as I expected.
I am very perplexed with these statements in the book.
All this time, my understanding of the statement char *tabheader = "Sound"; is same as const char *tabHeader = "Sound"; Now, this book is saying that is dependent on which gcc compiler
My question is this: Which GCC compiler allows this code to run?
What is your opinion on this?
Does this also belong to undefined behavior?
This would work in versions of GCC prior to 4.0 if you use the -fwritable-strings option when compiling. This option was removed in 4.0.
It would work on systems that don't store string literals in a protected part of memory. For example, the AVR port of GCC stores string literals in RAM and all RAM is writable, so you can probably write to them. In general, writing to a string literal is undefined behavior so you should not do it.
You mentioned you were confused about the difference between these two lines:
char *tabheader = "Sound";
const char *tabHeader = "Sound";
The main difference is that with the const qualifier, the compiler knows at compile time that you cannot write to the string so it will give you errors at compile time instead of undefined behavior at run time if you try to write to it.
gcc has many modes and compatibilities. Originally (1970s) in C, there was no const type and certainly no concept that a string literal was constant. It was occasional (but infrequent) practice in those days to use a string literal as a buffer initialization.
The eventual and slow evolution of string literals to being implied constants has caused pain with maintenance of ancient code which depends on earlier behavior. Gcc's philosophy apparently enables old behavior with a compiler flag. For example, from man gcc for gcc 6.3.1 20161221 (Red Hat 6.3.1-1), the section on -std is (partially):
-std=
Determine the language standard. This option is currently only
supported when compiling C or C++.
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.
A value for this option must be provided; possible values are
c90
c89
iso9899:1990
Support all ISO C90 programs (certain GNU extensions that
conflict with ISO C90 are disabled). Same as -ansi for C code.
iso9899:199409
ISO C90 as modified in amendment 1.
c99
c9x
iso9899:1999
iso9899:199x
ISO C99. This standard is substantially completely supported,
modulo bugs and floating-point issues (mainly but not entirely
relating to optional C99 features from Annexes F and G). See
<http://gcc.gnu.org/c99status.html> for more information. The
names c9x and iso9899:199x are deprecated.
c11
c1x
iso9899:2011
ISO C11, the 2011 revision of the ISO C standard. This
standard is substantially completely supported, modulo bugs,
floating-point issues (mainly but not entirely relating to
optional C11 features from Annexes F and G) and the optional
Annexes K (Bounds-checking interfaces) and L (Analyzability).
The name c1x is deprecated.
gnu90
gnu89
GNU dialect of ISO C90 (including some C99 features).
gnu99
gnu9x
GNU dialect of ISO C99. The name gnu9x is deprecated.
gnu11
gnu1x
GNU dialect of ISO C11. This is the default for C code. The
name gnu1x is deprecated.
c++98
c++03
The 1998 ISO C++ standard plus the 2003 technical corrigendum
and some additional defect reports. Same as -ansi for C++ code.
gnu++98
gnu++03
GNU dialect of -std=c++98.
c++11
c++0x
The 2011 ISO C++ standard plus amendments. The name c++0x is
deprecated.
gnu++11
gnu++0x
GNU dialect of -std=c++11. The name gnu++0x is deprecated.
c++14
c++1y
The 2014 ISO C++ standard plus amendments. The name c++1y is
deprecated.
...
Note that there are other compiler flags which control acceptance or rejection or alternate handling of K&R function headers and similar aspects.

getchar_unlocked() implicit declaration in C99

Using getchar_unlocked and compiling with --std=c99 flag gives warningas follows-
warning: implicit declaration of function ‘getchar_unlocked’ [-Wimplicit-function-declaration]
Does not give any warning if compiled without flag.Is there any way to work around with it ?
Starting from C99 you must have a visible function prototype before calling a function. While the earlier C standard would just stupidly assume that any function unknown to the compiler has the format int func (params), which in turn would cause severe bugs most of the time.
Properly declare a prototype for getchar_unlocked and the bug will go away.
Note that there is no such function present in any standard library. It seems you might have to include some non-standard library for the compiler to find the function.
_unlocked versions of get... functions are POSIX extensions. They are not part of the standard functions of C99. The full list of get... functions is given in 7.19.1.5: getwc, getwchar, getc, getchar, and gets (deprecated).
When the function is not on this list, C99-compliant compiler must warn you that your program may not compile with other C99-compliant compilers.
Dialect selection options like -ansi and -std=c99 cause the compiler to define certain macros (in addition to altering the accepted dialect).
Library header files react to those macros.
Precisely how they react is quite system-dependent (the compiler doesn't provide a C library), but a common behavior you can broadly expect is that if you use one of these flags alone (without any other "feature selection macro"), it has the effect of hiding the declarations of functions, macros and other global symbols which are not in the specified ISO C dialect.
ISO C knows nothing about getchar_unlocked. The presence of such a declaration in <stdio.h> (normally an ISO C header) is a POSIX extension, which is basically nonconforming, since getchar_unlocked is an identifier that strictly conforming C programs can use, even if they include <stdio.h>. When you use -ansi or -std=c99, the <stdio.h> header listens up and whips itself into ISO-C-conforming shape, hiding such extensions.
On well-behaved POSIX systems, you can request that you want an ISO C dialect and that you want certain rudimentary 1990-ish POSIX features to be visible in header files, for instance like this:
gcc -std=c99 -D_POSIX_SOURCE ...
^^^^^ "feature selection macro"
There is a whole science to these feature selection macros, too broad for this question and answer; some forms of them have values, like -D_XOPEN_SOURCE=500. _POSIX_SOURCE doesn't need an argument; it is just defined or not, but _POSIX_C_SOURCE is numeric.
I just checked glibc and Cygwin: on both, _POSIX_SOURCE is enough to reveal the getchar_unlocked declaration. It is quite old, dating back to POSIX.1 1996.
Beware: on some systems, multiple feature selection macros don't play along reasonably; they give you a set intersection rather than union, so that -D_POSIX_SOURCE and -D_BSD_SOURCE together end up meaning "Declare to me only those handful of functions that are specific to classic BSD that have been standardized in POSIX too", which means that next to nothing is declared.
getchar_unlocked is not a C standard function.
Compiling it forcing c99 standard does not support it natively.

Does changing the target C standard achieve anything?

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

C99 not default C- version for GCC?

Why does not GCC compile the C99 by default? I mean why is it necessary to add --std=c99 flag
everytime a code in C99 is written?
Edit: As of GCC 5, -std=gnu11 is the default. See Porting to GCC 5.
See C Dialect Options, gnu89 is the default.
`gnu89'
GNU dialect of ISO C90 (including some
C99 features). This is the default for
C code.
As #tsv mentioned, ISO C99 is not fully supported yet:
`c99'
`c9x'
`iso9899:1999'
`iso9899:199x'
ISO C99. Note that this standard is not yet fully supported; see http://gcc.gnu.org/c99status.html for more information. The names `c9x' and `iso9899:199x' are deprecated.
And also:
`gnu99'
`gnu9x'
GNU dialect of ISO C99. When ISO C99 is fully implemented in GCC, this will become the default. The name `gnu9x' is deprecated.
Perhaps because it still isn't fully implemented - see C99 status.
It also could be argued C99 features haven't been widely adopted, although that's something of a circular argument.
Use the command c99 to compile C programs.
The current POSIX standard specifies the command c99, so it should be available in most Unix-like systems.
The reason is that default configurations of gcc take a really long time to be changed, since every time a default configuration is changed, it can potentially break the compilation of valid programs (in this case valid c89 programs which are invalid in c99). Starting with gcc 5.0, the default C standard used by gcc will be gnu11, which is c11 with gnu extensions (see here):
The default mode for C is now -std=gnu11 instead of -std=gnu89.

Resources