The C preprocessor (cpp
) seems like it should handle this code correctly:
#define A 1 // hello there
int foo[A];
I would expect to replace A
with 1
.
What happens is that A
is replaced with 1 // hello there
, which results in the following output from cpp -std=c99 test.c
:
# 1 "test.c"
int foo[1 // hello there];
Which is not valid C and fails to compile.
How can I get cpp
to perform the proper replacement?
Note on compiler: Using cpp
from the latest (8.2.1, Dec 2016) Xcode on mac, so I doubt it's due to an outdated compiler.
Somewhat to my surprise, I can reproduce the problem on my Mac (macOS Sierra 10.12.2;
Apple LLVM version 8.0.0 (clang-800.0.42.1)
) using/usr/bin/cpp
which is the XCodecpp
— but not using GNUcpp
(which I invoke using justcpp
).Workarounds include:
This uses the
clang
wrappergcc
to run the C preprocessor and correctly handles the version. You could add a-v
option and see what it runs; I didn't see it runningcpp
per se (it runsclang -cc1 -E
with lots of other information).You can also use:
It's effectively the same thing.
You could also install GCC and use that instead of XCode. There are questions with answers about how to get that done (but it isn't for the faint of heart).
From the C11 specification (emphasis added):
where note 6) states:
Hence, an implementation conforming to the C11 specification is not required to have a separate preprocessor. Which means that the
cpp
command can do whatever it wants. And the compiler driver is allowed to perform phases 1 through 3 be any means it wants. So the correct way to get the output after preprocessing is to invoke the compiler driver withcc -E
.Note that
//
is not a valid C90 comment. It was introduced in C99, so make sure your compiler and pre-processor know they're to use the C99 standard. In many that's-std=c99
. (The question was since edited to make that clear)Next is that I don't believe the pre-processor cares about comments. From the 6.10 of the C99 spec shows the grammar of preprocessor directives and nowhere does it mention comments...The ANSI C standard makes it clear comments are supposed to be replaced in 2.1.1.2 "Translation Phases" phase 3 (5.1.1.2 in C99). (Drawing from this other answer).
Older tools might not have followed that either because they predate any C standard or they had bugs or they interpreted the standard differently. They've likely retained those bugs/quirks for backwards compatibility. Testing with
clang -E -std=c99
vs/usr/bin/cpp -std=c99
confirms this. They behave differently despite being the same compiler under the hood.I suspect invoking clang as
/usr/bin/cpp
is causing bug/quirk compatibility with the original behavior ofcpp
established back when the behavior was unclear.I guess the lesson here is to use
cc -E
rather thancpp
to ensure consistent behavior.