18

The Wikipedia entry for the C Preprocessor states:

The language of preprocessor directives is agnostic to the grammar of C, so the C preprocessor can also be used independently to process other types of files.

How can this be done? Any examples or techniques?

EDIT: Yes, I'm mostly interested in macro processing. Even though it's probably not advisable or maintainable it would still be useful to know what's possible.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
user4812
  • 5,942
  • 9
  • 30
  • 35
  • 5
    What do you need done with the preprocessor? If you just need macro processing, you could use m4: http://www.gnu.org/software/m4/ – dwhall Jul 08 '09 at 18:40
  • woah, m4? I mean.. seriously? I thought it was a well forgotten thing for most of the people. Where is it used nowadays? One thing I know, is that it's used to compile sendmail's .cf files. – shylent Jul 08 '09 at 18:43
  • 1
    m4 may still be used when you run configure; make; make install. Look closely at configure. – S.Lott Jul 08 '09 at 18:47
  • my first intrduction to m4 was that it was used to make electronic device circuit board footprint designs for the gEDA design software. I think it's still used in that suite (which IMHO is one of the best, and is open source to boot). – rmeador Jul 08 '09 at 19:30
  • 1
    @dwhall I followed your & others' advice yesterday and used M4 to implemented GL ES/Metal-hybrid shaders for a project I'm working on.  Throughout getting it working I came to two realizations: 1. I have used M4 before (for Sendmail) and I hated it; 2. compared to simpler & widely-used tools like the C preprocessor and modern more-robust tools like ERB, M4 is an antiquated, kludgey piece of junk. _`dnl`? Seriously? I can't provide a flag to just strip whitespace from non-output-producing lines? And don't get me started on trying to get both `float3`→`vec` & `float3(1.0)`→`vec3(1.0)` working._ – Slipp D. Thompson Mar 04 '17 at 20:48
  • @dwhall Side-note: `erb`'s `-T` flag (trim mode) is a godsend.  No modern general-purpose macroing/templating tool should be without something like this.  See: http://manpages.ubuntu.com/manpages/zesty/man1/erb.1.html – Slipp D. Thompson Mar 04 '17 at 21:40
  • m4 is not your friend. If it were, we'd all be calling it m8. – Braden Best Jul 01 '18 at 05:46

12 Answers12

20

You can call CPP directly:

cpp <file>

Rather than calling it through gcc:

gcc -E filename

Do note however that, as mentioned in the same Wikipedia article, C preprocessor's language is not really equipped for general-purpose use:

However, since the C preprocessor does not have features of some other preprocessors, such as recursive macros, selective expansion according to quoting, string evaluation in conditionals, and Turing completeness, it is very limited in comparison to a more general macro processor such as m4.

Have you considered dabbling with a more flexible macro processing language, like the aforementioned m4 for instance?

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
kjfletch
  • 5,394
  • 3
  • 32
  • 38
  • 2
    +1 for the reference to `m4`. This has traditionally been the preprocessor of choice for complex tasks; CPP is very primitive by comparison. – ephemient Jul 08 '09 at 19:32
  • 6
    You can't really have "fun" with CPP. m4 on the other hand is a minefield of enjoyment; just have to get over the initial hump of pain. – kjfletch Jul 08 '09 at 20:14
  • m4 does look interesting, thanks to everyone who's mentioned that. – user4812 Jul 08 '09 at 21:28
  • 1
    Just make sure you don't use m4 macros in standard C/C++ code, or the coder coming after you will hate your guts for it. ;-) – DevSolar Jul 09 '09 at 05:14
2

Many C compilers have a flag that tells them to only preprocess. With gcc it's the -E flag. eg:

$ gcc -E -                 
#define FOO foo
bar FOO baz

will output:

# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "<stdin>"

bar foo baz

With other C compilers you'll have to check the manuals to see how to swithc to preprocess-only mode.

Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
2

For example, Assembler. While many assemblers have their own way to #include headers and #define macros, it can be useful to use the C preprocessor for this. GNU make, for example, has implicit rules for turning *.S files into *.s files by running the preprocessor ('cpp'), before feeding the *.s file to the GNU assembler ('as').

DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • Although depending on the case of a single letter of the file name was a poor design choice there... where I've done the equivalent thing in other projects, I've used .asm or .src for the "real" source code, and the standard .s for the code emitted by cpp. Unfortunately there are many developers (even using Gnu tools) that live on file systems that can't distinguish names by case alone. NTFS defaults to be case preserving, but not case sensitive, for instance. – RBerteig Jul 08 '09 at 22:15
  • I didn't say it was a *smart* choice. ;-) – DevSolar Jul 09 '09 at 05:14
  • Actually GNU Make doesn't run it through the C preprocessor (at least not directly), it runs it through the C compiler `$(CC)`, this method works on case sensitive file systems as it doesn't require two files similarly named. – Joe D Jul 29 '10 at 17:51
  • @Joe D: Wrong on both accounts. The implicit make rule is "to make N.s from N.S", and the call is `$(CPP) $(CPPFLAGS)`. (GNU make manual, Catalogue of Implicit Rules.) – DevSolar Jul 30 '10 at 04:52
2

Yes, it can be done by parsing your own language through the gcc preprocessor (e.g. 'gcc -E').

We have done this on my job with our our, specific language. It has quite some advantages:

  • You can use C's include statements (#include) which is very powerful
  • You can use your #ifdef constructions
  • You can define Constants (#define MAGIC_NUMBER 42) or macro functions (#define min(x,y) ( (x( < (y) ? (x) : (y))

... and the other things in the c processor.

HOWEVER, you also inherit the unsafe C constructions, and having a preprocessor not integrated with your main language is the cause of it. Think about the minimum macro and doing something like :

a = 2;
b = 3;

c = min(a--, b--);

Just think what value a and b will have after the min function?

Same is true about the non-typed constants that you introduce

See the Safer C book for details.

Roalt
  • 8,330
  • 7
  • 41
  • 53
  • Re your source code example… `2`, because postfix-increment/decrement operators suck, not because of anything that has to do with C's macro preprocessor.  Like JavaScript, there exist a number of “C: The Bad Parts”, and postfix-`++`/`--` are a good example.  My suggestion is to just forget that they exist and **only use prefix-`++`/`--`** _(e.g. `min(--a, --b);` and `for (int i = 0; i < count; ++i)`)_. – Slipp D. Thompson Mar 04 '17 at 21:00
  • @SlippD.Thompson I disagree. While the behavior of postfix increment and decrement is... *unique,* it's still useful as syntax sugar for cases where you need to simultaneously have the old value while incrementing the current value, like pushing/popping a stack. `*stack++ = myvar` / `myvar = *--stack`. Also, it doesn't matter *what* you put in that macro, the behavior is going to be different from a function regardless. Your example expands to (correcting Roalt's typo in the min macro) `( (--a) < (--b) ? (--a) : (--b) )`, or (assuming left-to-right evaluation) `1 < 2 ? 0 : 1`, which is wrong. – Braden Best Jul 01 '18 at 06:03
  • #define MIN(a, b) ({ typeof(a) _a = a; typeof(b) _b = _b; _a > _b ? _a : _b;}) – Michal Butterweck Aug 16 '18 at 17:18
1

Usually you can invoke the C compiler with an option to preprocess only (and ignore any #line statements). Take this as a simple example:

<?php
function foo()
{
#ifdef DEBUG
    echo "Some debug info.";
#endif
    echo "Foo!";
}

foo();

We define a PHP source file with preprocess statements. We can then preprocess it (gcc can do this, too):

cl -nologo -EP foo.php > foo2.php

Since DEBUG is not the defined the first echo is stripped. Plus here is that lines beginning with # are comments in PHP so you don't have to preprocess them for a "debug" build.

Edit: Since you asked about macros. This works fine too and could be used to generate boilerplate code etc.

gix
  • 5,737
  • 5
  • 34
  • 40
  • 1
    are people really doing this sort of things? – Geo Jul 08 '09 at 19:28
  • 1
    @Geo, yes they are. Perl has (or used to have) a command-line option to run the perl script through CPP before letting the parser at it, for instance. If all you need is some #ifdef handling to turn blocks of code on and off or #include to share source lines, cpp is actually a pretty good choice of tool. – RBerteig Jul 08 '09 at 22:10
1

Using Microsoft's compiler, I think (I just looked it up, haven't tested it) that it's the /P compiler option.

Other compilers presumably have similar options (or, for some compilers the preprocessor might actually be a different executable, which is usually run implicitly by the compiler but which you can also run explicitly separately).

ChrisW
  • 54,973
  • 13
  • 116
  • 224
1

Assuming you're using GCC, You can take any plain old text file, regardless of its contents, and run:

gcc -E filename

Any preprocessor directives in the file will be processed by the preprocessor and GCC will then exit.

The point is that it doesn't matter what the actual content of the text file is, since all the preprocessor cares about is its own directives.

Jeff L
  • 6,108
  • 3
  • 23
  • 29
1

I have heard of people using the C pre-processor on Ada code. Ada has no preprocessor, so you have to do something like that if you want to preprocess your code.

However, it was a concious design decision not to give it one, so doing this is very un-Ada. I wouldn't suggest anyone do this.

Community
  • 1
  • 1
T.E.D.
  • 44,016
  • 10
  • 73
  • 134
1

A while ago I did some work on a project that used imake for makefile generation. As I recall, it was basically the c preprocessor syntax to generate the make files.

Caleb Huitt - cjhuitt
  • 14,785
  • 3
  • 42
  • 49
1

The C preprocessor can also be invoked by the Glasgow Haskell Compiler (GHC) prior to compiling Haskell code, by passing the -cpp flag.

Stephan202
  • 59,965
  • 13
  • 127
  • 133
0

You could implement the C preprocessor in the compiler for another language.

You could use it to preprocess any sort of text file, but there's much better things for that purpose.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
0

Basically what it's saying is that preprocessors have nothing to do with C syntax. They are basically simple parsers that follow a set of rules. So you could use preprocessors kind of like you'd use sed or awk for some silly tasks. Don't ask me why you'd ever want to do it though.

For example, on a text file:

#define pi 3.141

pi is not an irrational number.

Then you run the preprocessor & you'd get.

3.141 is not an irrational number.

dborba
  • 653
  • 6
  • 15