2

Is it possible to put #ifndef at the top of a c file? Basically I need to check whether a certain preprocessor constant was declared when running the program and my program will change accordingly.

I need to check if -D DESCENDING_ORDER=1 is added as an argument (doesn't matter what value given).

I have this code at the top of my main c file:

#ifndef DESCENDING_ORDER
int ascending = 1;
#else
int ascending = 0;
#endif

Works when compiling by itself, but I get errors when I try compiling with a Makefile, something along the lines of "expected identifier before 'int' for int ascending = 1.

Thanks.

EDIT - Added Makefile code

CC=gcc
CFLAGS=-g -Wall
INC=-include
RES_OBS=res.o
LIBS=
all: res

res:    $(RES_OBS)

    $(CC) $(CFLAGS) -o res $(RES_OBS) $(LIBS) $(INC) res.h -D DESCENDING_ORDER=1

clean:
        rm -f *.o

clobber:
        make clean
        rm -f res

Kind of guessed and added $(INC)....DESCENDING_ORDER=1 to the end of the command, so that's probably why it's not working. Command I'm using without makefile:

gcc res -include res.h -D DESCENDING_ORDER=1

EDIT 2 - Had a little play with different arguments and found that I get the same error if I remove -include res.h in the command. Still not sure how to correctly reference the header file in the makefile? I've added the #include "res.h" in my res.c file but still get the error.

AstroCB
  • 12,337
  • 20
  • 57
  • 73
Travv92
  • 791
  • 4
  • 14
  • 27
  • It is possible and standard practice. You should show your `Makefile` rules. Perhaps using `remake -x` to debug your `Makefile` should help. Give exactly the source code and error messages. – Basile Starynkevitch Mar 23 '13 at 07:45
  • Noted, added to post. – Travv92 Mar 23 '13 at 08:00
  • You should give much more details, e.g. the exact error message and the real `res.c` & `res.h` files. – Basile Starynkevitch Mar 23 '13 at 08:50
  • The real files would be too big to post here, so I've just included where the error is pointing me to. This is the error: `gcc -g -Wall -DDESCENDING_ORDER=1 -c -o res.o res.c.. res.c:10:1 error expected ';', identifier or '(' before 'int'.. make: *** [res.o] Error 1` and line 10 char 1 is where `int ascending = 0` is. – Travv92 Mar 23 '13 at 09:32
  • Probably the issue is just before that, in the preprocessed form. Maybe a missing semicolon or closing brace in some previously included file. – Basile Starynkevitch Mar 23 '13 at 11:35
  • Definitely not, I can compile and run the code successfully using `gcc -g -Wall res.c -include res.h -DDESCENDING_ORDER=1; ./a.out` – Travv92 Mar 23 '13 at 12:01
  • What is the contents of res.h? This is most likely causing the problem. – Johannes Overmann Mar 26 '13 at 08:39

2 Answers2

3

There is a typo in your Makefile since $(CLAGS) should be $(CFLAGS). Learn a lot more about make, notably by running make -p which shows you the many built-in rules to make and use them (e.g. consider using $(COMPILE.c) and $(LINK.c) etc..)

Don't forget to add -Wall to your CFLAGS, because you want all the warnings from the compiler. You probably want debugging information too, so add g also.

On Linux, I do recommend using remake for debugging Makefile-s by running remake -x which helps a lot.

Standard practices are:

  • avoid passing -include to gcc, instead, add a#include "res.h" near the beginning of relevant *.c source files

  • glue the -D to the defined symbol, e.g. -DDESCENDING_ORDER=1

  • add in your Makefile the dependencies on relevant object files to the newly #include-d file res.h; notice that these dependencies could be automatically generated (by passing e.g. -MD to gcc, etc etc...)

  • pass the -DDESCENDING_ORDER=1 thru CFLAGS or better CPPFLAGS

Don't forget that the order of program arguments to gcc matters a lot.

addenda

You may want to generate the preprocessed form res.i of your source code res.c using gcc -C -E and you could have a rule like

  res.i: res.c res.h
           $(CC) -C -E $(CFLAGS) $(CPPFLAGS) $^ -o $@

then do make res.i and examine with some editor or pager (perhaps less) the preprocessor output res.i ; alternatively, do that on the command line

  gcc -C -E -I. -DDESCENDING_ORDER=1  res.c | less

you could remove the generated line information and do

  gcc -C -E -I. -DDESCENDING_ORDER=1  res.c | grep -v '^#' > res_.i
  gcc -Wall -c res_.i

The point is that the preprocessing in C is a textual operation, and your preprocessed form is wrong.

BTW very recent Clang/LLVM (version 3.2) or GCC (just released version 4.8) compilers give you much better messages regarding preprocessing.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Thanks Basile. I definitely have `CFLAGS` instead of `CLAGS`, must have copied it over and accidently deleted the letter. I've removed `-include` and added `#include "result.h"` in my code and added `-DDESCENDING_ORDER=1` to `CFLAGS` but I'm still receiving the error! – Travv92 Mar 23 '13 at 08:27
0

The code is fine. The error you're getting when using a Makefile has to do with something else (it's hard to be sure without seeing what comes before the #ifndef and seeing the Makefile).

NPE
  • 486,780
  • 108
  • 951
  • 1,012