I'm writing some serial code on a raspberry pi and switched to C99. When I did I started getting the error "error: ‘CRTSCTS’ undeclared (first use in this function)"
$ c99 -M serial01.c | grep termios.h
/usr/include/termios.h /usr/include/arm-linux-gnueabihf/bits/termios.h \
$ gcc -M serial01.c | grep termios.h
/usr/include/termios.h /usr/include/arm-linux-gnueabihf/bits/termios.h \
using -M reveals 2 termios.h headers. the former does not contain a definition for CRTSCTS and the latter does.
I assume the standard c89 is using the good one and c99 not but I'm not sure since the result of the -M call is identical. Can anyone explain to me why this is happening when I switch to C99 and how to fix it?
-std=gnu99
is the solution. More detailed below.
Result of the gcc/c99 -M call is identical but it does not mean anything! The explanation of this behavior are preprocessor macros (specifically GNU extensions, like said Mat).
In detail:
cat -n main.c
1 #include <termios.h>
2
3 int printf(const char *, ...);
4
5 int main(void)
6 {
7 printf("%d\n", CRTSCTS);
8 return 0;
9 }
gcc main.c -o main --std=c89 -> 'CRTSCTS' undeclared compilation error
gcc main.c -o main --std=cgnu89 -> successfully compiled
This behavior is the same for c99 and gnu99!
Like said Cameron, -M output is identical:
gcc -M --std=c89 main.c | grep termios.h | nl
1 main.o: main.c /usr/include/termios.h /usr/include/features.h \
2 /usr/include/arm-linux-gnueabihf/bits/termios.h
gcc -M --std=gnu89 main.c | grep termios.h | nl
1 main.o: main.c /usr/include/termios.h /usr/include/features.h \
2 /usr/include/arm-linux-gnueabihf/bits/termios.h \
CRTSCTS is defined in the bits/termios.h when __USE_MISC is defined
1 #ifdef __USE_MISC
2 # define CIBAUD 002003600000 /* input baud rate (not used) */
3 # define CMSPAR 010000000000 /* mark or space (stick) parity */
4 # define CRTSCTS 020000000000 /* flow control */
Let's look at __USE_MISC.
gcc -M /usr/include/termios.h | nl
1 termios.o: /usr/include/termios.h /usr/include/features.h \
2 /usr/include/arm-linux-gnueabihf/bits/predefs.h \
3 /usr/include/arm-linux-gnueabihf/sys/cdefs.h \
4 /usr/include/arm-linux-gnueabihf/bits/wordsize.h \
5 /usr/include/arm-linux-gnueabihf/gnu/stubs.h \
6 /usr/include/arm-linux-gnueabihf/bits/types.h \
7 /usr/include/arm-linux-gnueabihf/bits/typesizes.h \
8 /usr/include/arm-linux-gnueabihf/bits/termios.h \
9 /usr/include/arm-linux-gnueabihf/sys/ttydefaults.h
First one, features.h, contains definition of __USE_MISC, but only when _BSD_SOURCE or _SVID_SOURCE is defined
grep 'define __USE_MISC' /usr/include/features.h -B 1 | nl
1 #if defined _BSD_SOURCE || defined _SVID_SOURCE
2 # define __USE_MISC 1
and _BSD_SOURCE and _SVID_SOURCE is defined when _GNU_SOURCE or 'nothing' is defined
1 #ifdef _GNU_SOURCE
2 # undef _ISOC95_SOURCE
3 # define _ISOC95_SOURCE 1
4 # undef _ISOC99_SOURCE
5 # define _ISOC99_SOURCE 1
6 # undef _POSIX_SOURCE
7 # define _POSIX_SOURCE 1
8 # undef _POSIX_C_SOURCE
9 # define _POSIX_C_SOURCE 200809L
10 # undef _XOPEN_SOURCE
11 # define _XOPEN_SOURCE 700
12 # undef _XOPEN_SOURCE_EXTENDED
13 # define _XOPEN_SOURCE_EXTENDED 1
14 # undef _LARGEFILE64_SOURCE
15 # define _LARGEFILE64_SOURCE 1
16 # undef _BSD_SOURCE
17 # define _BSD_SOURCE 1
18 # undef _SVID_SOURCE
19 # define _SVID_SOURCE 1
20 # undef _ATFILE_SOURCE
21 # define _ATFILE_SOURCE 1
22 #endif
23 /* If nothing (other than _GNU_SOURCE) is defined,
24 define _BSD_SOURCE and _SVID_SOURCE. */
25 #if (!defined __STRICT_ANSI__ && !defined _ISOC99_SOURCE && \
26 !defined _POSIX_SOURCE && !defined _POSIX_C_SOURCE && \
27 !defined _XOPEN_SOURCE && !defined _BSD_SOURCE && !defined _SVID_SOURCE)
28 # define _BSD_SOURCE 1
29 # define _SVID_SOURCE 1
30 #endif
As requested by xtreye and since the official answer does explain but doesn't actually explicitly list the solution - We both fixed this by using a -std=gnu99
compiler flag.
Hope that helps.
You can use -D_DEFAULT_SOURCE -std=c99
instead of -std=gnu99
, at least in gentoo. It "seems more standard" to me.
Searching around in /usr/include
, I see:
/usr/include/features.h
52 _DEFAULT_SOURCE The default set of features (taking precedence over
53 __STRICT_ANSI__).
61 The `-ansi' switch to the GNU C compiler, and standards conformance
62 options such as `-std=c99', define __STRICT_ANSI__. If none of
63 these are defined, or if _DEFAULT_SOURCE is defined, the default is
64 to have _POSIX_SOURCE set to one and _POSIX_C_SOURCE set to
65 200809L, as well as enabling miscellaneous functions from BSD and
66 SVID. If more than one of these are defined, they accumulate. For
67 example __STRICT_ANSI__, _POSIX_SOURCE and _POSIX_C_SOURCE together
68 give you ISO C, 1003.1, and 1003.2, but nothing else.
383 #if defined _DEFAULT_SOURCE
384 # define __USE_MISC 1
385 #endif
Other files, such as in /usr/include/boost/*
and /usr/include/eigen3/*
also make use of _DEFAULT_SOURCE
.
Also, the link provided by @CamW in a comment is quite enlightening:
* The macros that you most likely need to use in modern source code are _POSIX_C_SOURCE (for definitions from various versions of POSIX.1), _XOPEN_SOURCE (for definitions from various versions of SUS), _GNU_SOURCE (for GNU and/or Linux specific stuff), and _DEFAULT_SOURCE (to get definitions that would normally be provided by default). _DEFAULT_SOURCE (since glibc 2.19) This macro can be defined to ensure that the "default" definitions are provided even when the defaults would otherwise be disabled, as happens when individual macros are explicitly defined, or the compiler is invoked in one of its "standard" modes (e.g., cc -std=c99). Defining _DEFAULT_SOURCE without defining other individual macros or invoking the compiler in one of its "standard" modes has no effect. The "default" definitions comprise those required by POSIX.1-2008 and ISO C99, as well as various definitions originally derived from BSD and System V. On glibc 2.19 and earlier, these defaults were approximately equivalent to explicitly defining the following: cc -D_BSD_SOURCE -D_SVID_SOURCE -D_POSIX_C_SOURCE=200809
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With