C preprocessing fails to stop immediately after an #error - c

My question today should not be very much complicated, but I simply can't find a reason/solution. As a small, reproducible example, consider the following toy C code
#define _state_ 0
#if _state_ == 1
int foo(void) {return 1;}
#else
/* check GCC flags first
note that -mfma will automatically turn on -mavx, as shown by [gcc -mfma -dM -E - < /dev/null | egrep "SSE|AVX|FMA"]
so it is sufficient to check for -mfma only */
#ifndef __FMA__
#error "Please turn on GCC flag: -mfma"
#endif
#include <immintrin.h> /* All OK, compile C code */
void foo (double *A, double *B) {
__m256d A1_vec = _mm256_load_pd(A);
__m256d B_vec = _mm256_broadcast_sd(B);
__m256d C1_vec = A1_vec * B_vec;
}
#endif
I am going to compile this test.c file by
gcc -fpic -O2 -c test.c
Note I did not turn on GCC flag -mfma, so the #error will be triggered. What I would expect, is that compilation will stop immediately after GCC sees this #error, but this is what I got with GCC 5.3:
test.c:14:2: error: #error "Please turn on GCC flag: -mfma"
#error "Please turn on GCC flag: -mfma"
^
test.c: In function ‘foo’:
test.c:22:11: warning: AVX vector return without AVX enabled changes the ABI [-Wpsabi]
__m256d A1_vec = _mm256_load_pd(A);
^
GCC does stops, but why does it also pick up a line after #error? Any explanation? Thanks.
For people who want to try, there are some hardware requirement. You need an x86-64 with AVX and FMA instruction sets.

I have a draft copy of the C ISO spec, and in §4/4 - it states
The implementation shall not successfully translate a preprocessing translation unit containing a #error preprocessing directive unless it is part of a group skipped by conditional inclusion.
Later on, in §6.10.5, where #error is formally defined, it says
A preprocessing directive of the form
# error pp-tokens opt new-line
causes the implementation to produce a diagnostic message that includes the specified
sequence of preprocessing tokens.
In other words, the spec only requires that any code that has an #error just needs to fail to compile and report an error message along the way, not that the compilation immediately needs to terminate as soon as #error is reached.
Given that it's considered good practice to always check the top-level errors reported by a compiler before later ones, I'd imagine a competent programmer who saw a string of errors beginning with an #error directive would likely know what was going on.

Related

Variables conflict between Makefile and C code

In my C Makefile I have the following lines:
ifeq ($(VERBOSE_PRINT), TRUE)
CFLAGS += -D TRUE
else
CFLAGS += -D FALSE
endif
As you can tell by it's name, this flag indicated whether I should print debug statements or not.
In other place at my C code, I'm defining TRUE and FALSE with
#define FALSE 0
#define TRUE !FALSE
Then when I'm trying to compile my code, I get the following error:
types.h:6:0: error: "FALSE" redefined [-Werror]
#define FALSE 0
<command-line>:0:0: note: this is the location of the previous definition
If I delete the definition of TRUE and FALSE from my C code, my program get's crazy.
What's going on and how can I solve this conflict?
Thanks ahead.
You can't use the same name for two different incompatible things, so you'll need to change one of them. Most likely you want to change your Makefile, since what you have makes no sense. Something like:
ifeq ($(VERBOSE_PRINT), TRUE)
CFLAGS += -DDEBUG=1
else
CFLAGS += -DDEBUG=0
endif
Then in your C code you can have
#if DEBUG
printf( ... debugging messages ... )
#endif
On the compiler command line, -DXYZ is equivalent to -DXYZ=1 (POSIX c99). This means that with -DFALSE on the command line, you've got both #define FALSE 1 and #define FALSE 0, which is a non-benign redefinition. Benign redefinition of a macro is OK (meaning that the sequence of replacement tokens is the same in both the current and new definition — see C11 §6.10.3 Macro replacement ¶1-2).
You need to use a different variable in your code to decide whether to do printing:
#ifdef VERBOSE_PRINT
printf("Debugging!\n");
#endif
You can then use -DVERBOSE_PRINT on the command line to enable printing and leave it out to disable it. Alternatively, you can use:
#if VERBOSE_PRINT
printf("Debugging!\n");
#endif
Then your makefile can contain:
ifeq ($(VERBOSE_PRINT), TRUE)
CFLAGS += -DVERBOSE_PRINT=TRUE
else
CFLAGS += -DVERBOSE_PRINT=FALSE
endif
This technique is less common. It will work as if you have #define VERBOSE_PRINT 0 if you don't specify a value on the compiler command line (C11 §6.10.1 Conditional inclusion ¶4).

Why does GCC 9.1.0 sometimes complain about this use of strncpy()?

This is a 40-line MCVE (Minimal, Complete, Verifiable Example) — or something close to minimal — cut down from a 1675 line source file that originally included 32 headers (and most of those included multiple other headers — compiling it with gcc -H lists 464 headers from the project and the system, many of them several times). That file is working code that previously compiled without warnings (GCC 8.3.0), but not with GCC 9.1.0. All structure, function, type, variable names have been changed.
pf31.c
#include <string.h>
enum { SERVERNAME_LEN = 128 };
typedef struct ServerQueue
{
char server_name[SERVERNAME_LEN + 1];
struct ServerQueue *next;
} ServerQueue;
extern int function_under_test(char *servername);
#ifdef SUPPRESS_BUG
extern int function_using_name(char *name);
#endif /* SUPPRESS_BUG */
extern int GetServerQueue(const char *servername, ServerQueue *queue);
int
function_under_test(char *servername)
{
ServerQueue queue;
char name[SERVERNAME_LEN + 1];
if (GetServerQueue(servername, &queue) != 0)
return -1;
char *name_in_queue = queue.server_name;
if (name_in_queue)
strncpy(name, name_in_queue, SERVERNAME_LEN);
else
strncpy(name, servername, SERVERNAME_LEN);
name[SERVERNAME_LEN] = '\0';
#ifdef SUPPRESS_BUG
return function_using_name(name);
#else
return 0;
#endif /* SUPPRESS_BUG */
}
Compilation
When compiled using GCC 9.1.0 (on a Mac running macOS 10.14.5 Mojave, or on a Linux VM running RedHat 5.x — don't ask!), with the option -DSUPPRESS_BUG I get no error, but with the option -USUPPRESS_BUG, I get an error:
$ gcc -std=c11 -O3 -g -Wall -Wextra -Werror -DSUPPRESS_BUG -c pf31.c
$ gcc -std=c11 -O3 -g -Wall -Wextra -Werror -USUPPRESS_BUG -c pf31.c
In file included from /usr/include/string.h:417,
from pf31.c:1:
pf31.c: In function ‘function_under_test’:
pf31.c:30:9: error: ‘__builtin_strncpy’ output may be truncated copying 128 bytes from a string of length 128 [-Werror=stringop-truncation]
30 | strncpy(name, name_in_queue, SERVERNAME_LEN);
| ^~~~~~~
cc1: all warnings being treated as errors
$
When I compile using GCC 8.3.0, I get no errors reported.
Question
Two sides of one question:
Why does GCC 9.1.0 complain about the use of strncpy() when the code is compiled with -USUPPRESS_BUG?
Why doesn't it complain when the code is compiled with -DSUPPRESS_BUG?
Corollary: is there a way to work around this unwanted warning that works with older GCC versions as well as 9.1.0. I've not yet found one. There's also a strong element of "I don't think it should be necessary, because this is using strncpy() to limit the amount of data copied, which is what it is designed for".
Another variant
I have another non-erroring variant, changing the signature of the function_under_test() — here's a set of diffs:
11c11
< extern int function_under_test(char *servername);
---
> extern int function_under_test(char *servername, ServerQueue *queue);
20c20
< function_under_test(char *servername)
---
> function_under_test(char *servername, ServerQueue *queue)
22d21
< ServerQueue queue;
25c24
< if (GetServerQueue(servername, &queue) != 0)
---
> if (GetServerQueue(servername, queue) != 0)
27c26
< char *name_in_queue = queue.server_name;
---
> char *name_in_queue = queue->server_name;
This compiles cleanly regardless of whether SUPPRESS_BUG is defined or not.
As you can guess from the SUPPRESS_BUG terminology, I'm tending towards the view that this is bug in GCC, but I'm kinda cautious about claiming it is one just yet.
More about the the original code: the function itself was 540 lines long; the strncpy() block occurs about 170 lines into the function; the variable corresponding to name was used further down the function in a number of function call, some of which take name as an argument and supply a return value for the function. This corresponds more to the -DSUPPRESS_BUG code, except that in the 'real code', the bug is not suppressed.
This is a GCC bug tracked as PR88780. According to Martin's comment, this warning did not exist prior to GCC 8.
GCC is shipped with this known bug, as it is not deemed release-critical.
To be honest, I am not 100% sure it is the bug. The point is, there are known false-positives. If you feel like helping the GCC project, you can find the most appropriate bug among strncpy / Wstringop-truncation bugs and post your example there. It would be more helpful if you minimized it further (say, with creduce); minimizing the compile string is also appreciated (that would be rather trivial, I guess).
Several compilation warnings related to strncpy were found in GCC 9.0 and reported here and here.
One of them is the error mentioned in the question which seems to occur in the file string_fortified.h:
/usr/include/bits/string_fortified.h:106:10: warning: ‘__builtin_strncpy’ output may be truncated copying 16 bytes from a string of length 16 [-Wstringop-truncation]
106 | return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The response to this was given on April 15, 2019 was:
Thank you for the report, however as GCC 9 still under development. We do not see the above errors in the current stable GCC 7.4 or GCC 8.3. We appreciate the advanced notice, and will accept PRs to fix issues against GCC 9, but for now our target compiler is gcc stable.
So I believe the errors are probably a result of versions 9 and 9.1 being not stable versions. Hopefully they will be eliminated when these versions become stable.

Side effects in generic expressions

I'm doing some experiments with the new _Generic keyword and stumbled upon a special case regarding multiple evaluations. See the following:
#include <stdio.h>
#define write_char(c) _Generic(c, char: putchar, const char: putchar)(c)
int main(void)
{
const char *s = "foo";
write_char(*s++);
write_char(*s++);
write_char(*s++);
putchar('\n');
}
This compiles fine and produces the expected result with GCC:
$ gcc -std=c11 -Wall plusplus.c -o plusplus
$ ./plusplus
foo
On the other hand, Clang outputs a big honking warning:
$ clang -std=c11 plusplus.c -o plusplus
plusplus.c:9:18: warning: multiple unsequenced modifications to 's'
[-Wunsequenced]
write_char(*s++);
^~
plusplus.c:3:32: note: expanded from macro 'write_char'
#define write_char(c) _Generic(c, char: putchar, const char: putchar)(c)
...
Yet the result is as expected:
$ ./plusplus
foo
I checked the draft of the standard, which says (at p. 97 of the PDF):
The controlling expression of a generic selection is not evaluated.
This seems to precisely address the problem of side-effects in macros (e.g., MIN and MAX).
Now, can I safely ignore Clang's warning, or am I wrong?
As I mentioned in comments, you posted the question about two weeks after the bug was fixed in Clangs trunk. See revision rL223266 (December 3 2014). The fix is included in Clang 3.6.
Now, can I safely ignore Clang's warning, or am I wrong?
We already know that you're right, so here is a way to ignore pragmas in Clang for the
future:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsequenced"
write_char(*s++);
#pragma clang diagnostic pop
To do not repeat it on every use of the macro, you could put _Pragma in its body:
#define write_char(c) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wunsequenced\"") \
_Generic(c, char: putchar, const char: putchar)(c) \
_Pragma("clang diagnostic pop")
It seems that was a bug. It has now been solved since clang 3.6 onward as shown here.

How can I keep gcc -O2 from optimizing putchar out?

I have an application that uses a custom putchar(); which until now has been working fine.
I bumped up the optimization level of the application to -O2, and now my putchar isn't used.
I already use -fno-builtin, and based on some googling I added -fno-builtin-putchar to my CFLAGS, but that didn't matter.
Is there a "correct" way to get around this or do I have to go into my code and add something like
#define putchar myputchar
to be able to use -O2 and still pull in my own putchar() function?
edit--
Since my original post of this question, I stumbled on -fno-builtin-functions=putchar, as yet another gcc commandline option. Both this and the one above are accepted by gcc, but don't seem to have any noticeable effect.
edit more--
Experimenting further I see that gcc swallows -fno-builtin-yadayada also, so apparently the options parsing at the gcc front end is just passing the text after the second dash to some lower level which ignores it.
more detail:
Three files try1.c, try2.c and makefile...
try1.c:
#include <stdio.h>
int
main(int argc, char *argv[])
{
putchar('a');
printf("hello\n");
return(0);
}
try2.c:
#include <stdio.h>
int
putchar(int c)
{
printf("PUTCHAR: %c\n",c);
return(1);
}
makefile:
OPT=
try: try1.o try2.o
gcc -o try try1.o try2.o
try1.o: try1.c
gcc -o try1.o $(OPT) -c try1.c
try2.o: try2.c
gcc -o try2.o $(OPT) -c try2.c
clean:
rm -f try1.o try2.o try
Here's the output:
Notice that without optimization it uses the putchar I provided; but with -O2 it gets it from some other "magic" place...
els:make clean
rm -f try1.o try2.o try
els:make
gcc -o try1.o -c try1.c
gcc -o try2.o -c try2.c
gcc -o try try1.o try2.o
els:./try
PUTCHAR: a
hello
els:
els:
els:
els:make clean
rm -f try1.o try2.o try
els:make OPT=-O2
gcc -o try1.o -O2 -c try1.c
gcc -o try2.o -O2 -c try2.c
gcc -o try try1.o try2.o
els:./try
ahello
els:
Ideally, you should produce an MCVE (Minimal, Complete, Verifiable Example) or
SSCCE (Short, Self-Contained, Correct Example) — two names (and links) for the same basic idea.
When I attempt to reproduce the problem, I created:
#include <stdio.h>
#undef putchar
int putchar(int c)
{
fprintf(stderr, "%s: 0x%.2X\n", __func__, (unsigned char)c);
return fputc(c, stdout);
}
int main(void)
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
return 0;
}
When compiled with GCC 4.9.1 on Mac OS X 10.9.4 under both -O2 and -O3, my putchar function was called:
$ gcc -g -O2 -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Werror pc.c -o pc
$ ./pc <<< "abc"
putchar: 0x61
putchar: 0x62
putchar: 0x63
putchar: 0x0A
abc
$
The only thing in the code that might be relevant to you is the #undef putchar which removes the macro override for the function.
Why try1.c doesn't call your putchar() function
#include <stdio.h>
int
main(int argc, char *argv[])
{
putchar('a');
printf("hello\n");
return(0);
}
The function putchar() may be overridden by a macro in <stdio.h>. If you wish to be sure to call a function, you must undefine the macro.
If you don't undefine the macro, that will override anything you do. Hence, it is crucial that you write the #undef putchar (the other changes are recommended, but not actually mandatory):
#include <stdio.h>
#undef putchar
int main(void)
{
putchar('a');
printf("hello\n");
return(0);
}
Note that putchar() is a reserved symbol. Although in practice you will get away with using it as a function, you have no grounds for complaint if you manage to find an implementation where it does not work. This applies to all the symbols in the standard C library. Officially, therefore, you should use something like:
#include <stdio.h>
#undef putchar
extern int put_char(int c); // Should be in a local header
#define putchar(c) put_char(c) // Should be in the same header
int main(void)
{
putchar('a');
printf("hello\n");
return(0);
}
This allows you to leave your 'using' source code unchanged (apart from including a local header — but you probably already have one to use). You just need to change the implementation to use the correct local name. (I'm not convinced that put_char() is a good choice of name, but I dislike the my_ prefix, for all it is a common convention in answers.)
ISO/IEC 9899:2011 §7.1.4 Use of library functions
Each of the following statements applies unless explicitly stated otherwise in the detailed
descriptions that follow: …
Any function
declared in a header may be additionally implemented as a function-like macro defined in
the header, so if a library function is declared explicitly when its header is included, one
of the techniques shown below can be used to ensure the declaration is not affected by
such a macro. Any macro definition of a function can be suppressed locally by enclosing
the name of the function in parentheses, because the name is then not followed by the left
parenthesis that indicates expansion of a macro function name. For the same syntactic
reason, it is permitted to take the address of a library function even if it is also defined as
a macro.185) The use of #undef to remove any macro definition will also ensure that an
actual function is referred to. Any inv ocation of a library function that is implemented as
a macro shall expand to code that evaluates each of its arguments exactly once, fully
protected by parentheses where necessary, so it is generally safe to use arbitrary
expressions as arguments.186) Likewise, those function-like macros described in the
following subclauses may be invoked in an expression anywhere a function with a
compatible return type could be called.187)
185) This means that an implementation shall provide an actual function for each library function, even if it
also provides a macro for that function.
186) Such macros might not contain the sequence points that the corresponding function calls do.
187) Because external identifiers and some macro names beginning with an underscore are reserved,
implementations may provide special semantics for such names. For example, the identifier
_BUILTIN_abs could be used to indicate generation of in-line code for the abs function. Thus, the
appropriate header could specify
#define abs(x) _BUILTIN_abs(x)
for a compiler whose code generator will accept it.
In this manner, a user desiring to guarantee that a given library function such as abs will be a genuine
function may write
#undef abs
whether the implementation’s header provides a macro implementation of abs or a built-in
implementation. The prototype for the function, which precedes and is hidden by any macro
definition, is thereby revealed also.
Judging from what you observe, in one set of headers, putchar() is not defined as a macro (it does not have to be, but it may be). And switching compilers/libraries means that now that putchar() is defined as a macro, the missing #undef putchar means that things no longer work as before.

Is math within macro computed at compile time?

For example, does MIN_N_THINGIES below compile to 2? Or will I recompute the division every time I use the macro in code (e.g. recomputing the end condition of a for loop each iteration).
#define MAX_N_THINGIES (10)
#define MIN_N_THINGIES ((MAX_N_THINGIES) / 5)
uint8_t i;
for (i = 0; i < MIN_N_THINGIES; i++) {
printf("hi");
}
This question stems from the fact that I'm still learning about the build process. Thanks!
If you pass -E to gcc it will show what the preprocessor stage outputted.
gcc -E test.c | tail -n11
Outputs:
# 3 "test.c" 2
int main() {
uint8_t i;
for (i = 0; i < ((10) / 5); i++) {
printf("hi");
}
return 0;
}
Then if you pass -s flag to gcc you will see that the division was optimized out. If you also pass the -o flag you can set the output files and diff them to see that they generated the same code.
gcc -S test.c -o test-with-div.s
edit test.c to make MIN_N_THINGIES equal a const 2
gcc -S test.c -o test-constant.s
diff test-with-div.s test-constant.s
// for educational purposes you should look at the .s files generated.
Then as mentioned in another comment you can change the optimization flag by using -O...
gcc -S test.c -O2 -o test-unroll-loop.s
Will unroll the for loop even such that there isn't even a loop.
Preprocessor will replace MIN_N_THINGIES with ((10)/5), then it is up to the compiler to optimize ( or not ) the expression.
Maybe. The standard does not mandate that it is or it is not. On most compilers it will do after passing optimization flags (for example gcc with -O0 does not do it while with -O2 it even unrolls the loop).
Modern compilers perform even much more complicated techniques (vectorization, loop skewing, blocking ...). However unless you really care about performance, for ex. you program HPC, program real time system etc., you probably should not care about the output of the compiler - unless you're just interested (and yes - compilers can be a fascinating subject).
No. The preprocessor does not calculate macros, they're handled by the compiler. The preprocessor can calculate arithmetic expressions (no floating point values) in #if conditionals though.
Macros are simply text substitutions.
Note that the expanded macros can still be calculated and optimized by the compiler, it's just that it's not done by the preprocessor.
The standard mandates that some expressions are evaluated at compile time. But note that the preprocessor does just text splicing (well, almost) when the macro is called, so if you do:
#define A(x) ((x) / (S))
#define S 5
A(10) /* Gives ((10) / (5)) == 2 */
#undef S
#define S 2
A(20) /* Gives ((20) / (2)) == 10 */
The parenteses are to avoid idiocies like:
#define square(x) x * x
square(a + b) /* Gets you a + b * a + b, not the expected square */
After preprocessing, the result is passed to the compiler proper, which does (most of) the computation in the source that the standard requests. Most compilers will do a lot of constant folding, i.e., computing (sub)expressions made of known constants, as this is simple to do.
To see the expansions, it is useful to write a *.c file of a few lines, just with the macros to check, and run it just through the preprocessor (typically someting like cc -E file.c) and check the output.

Resources