Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

#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?

like image 676
Kenneth Avatar asked Jan 02 '12 11:01

Kenneth


2 Answers

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).

like image 115
Adam Zalcman Avatar answered Nov 07 '22 16:11

Adam Zalcman


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.

like image 36
thiton Avatar answered Nov 07 '22 15:11

thiton