Kenneth
Kenneth

Reputation: 1167

#define scope in multiple files

I have a main file like so:

main_a.c:

#define MAIN_A

#include <stdio.h>
#include "shared.h"

extern int i;
int main() {
  printf("i is: %d\n", i);
  return 0;
}

I want to use the define in shared.h like this:

shared.h

#if defined(MAIN_A)
# define A
#endif

So I can declare a variable according to whether the main file is present or not, like this:

shared.c

#include "shared.h"

#if defined(A)
int i = 1;
#else
int i = 0;
#endif

I build it using a makefile which looks like this:

Makefile:

all : a
    ./a

a : main_a.o shared.o
    gcc -o $@ $^

%.o : %.c
    gcc -c $<

However this prints

i is: 0

Now my question is: Why is it that the define seems to be lost when I compile the shared module? I know the main module is compiled first, so the define should have been resolved by the time shared.c is compiled.

One suspicion I have is that the preprocessor might get run at the start of each module build and not just at the start of the project. If this is correct is there a way of compiling more than a single module at a time to use the preprocessor as I attempt above?

Upvotes: 15

Views: 17402

Answers (5)

William Lowther
William Lowther

Reputation: 1

Defines almost work the same as any variable. If you want to share a variable across modules, you put it in a header. Same goes for #defines.

However, it is strange to use the #ifdef as you are always going to have main.c. You don't want to change the code each time you compile. Instead, use the method described by Adam Zalcman

Upvotes: -1

BLUEPIXY
BLUEPIXY

Reputation: 40145

Global define A

gcc main_a.c shared.c -DA

Upvotes: 0

Adam Zalcman
Adam Zalcman

Reputation: 27233

Preprocessor is run for each file before it is compiled, i.e. once for main_a.c and then again independently for shared.c. When shared.c is compiled MAIN_A is undefined.

Preprocessor can't be used the way you're attempting, i.e. remembering state across compilation units.

What you can do is define a name (for example MAIN_A) using the -Dcompiler option in your Makefile and test this name using preprocessor the same way you're doing it now. This way the definition takes place on the project level (in the Makefile) rather than on a compilation unit level (in a .c file).

Upvotes: 17

thiton
thiton

Reputation: 36049

Let me do the preprocessor's work here and expand all your macros. In main.c, MAIN_A is defined, so A is defined. Nothing depends on A in main.c, and i is extern.

In shared.c, MAIN_A and thereby A are undefined, and i is 0.

In short, the preprocessor cannot transport information between compilation units. That's good practice, because otherwise programs would quickly become unreadable and you would have to recompile all compilation units when one unit changes (because symbols might have changed). Resolve the issue by setting i explicitly in main:

 int main() {
     i = 1;
 }

It is more verbose, but is also much clearer to the reader. If you want to encapsulate, define a function InitializeShared. If you truly want to compile some code as a single compilation unit, make one of the files a header file and #include it into the other.

Upvotes: 1

Preet Sangha
Preet Sangha

Reputation: 65496

Yes you are right, they are completely separate compilation units.

MAIN_A is only defined in main_a.c

One thought that comes to mind is to cat the files together to make one compilation unit?

Upvotes: 0

Related Questions