2

Is it possible to have a header file compile differently in two different source files by using defines in the source files?

For example, if i have a single header included in two source files as in:

header.h:

#if FOO
#define BAR(x) f(x)
#else
#define BAR(x) g(x)
#endif

source1.cpp:

#define FOO 1
#include "header.h"

void a(int x) {
    BAR(x); // f(x)?
}

source2.cpp

#include "header.h"

void b(int x) {
    BAR(x); // g(x)?
}

Should this not compile so that function a performs f and function b performs g?

I'm trying to do this in XCode and Objective-C++. Both a and b perform g as if source1.cpp didn't define FOO.

Matti Jokipii
  • 561
  • 1
  • 6
  • 20

3 Answers3

2

Your macro is defined incorrectly correctly. The mistake is that it should be However I prefer to use #ifdef and not #if

#ifdef FOO
#define BAR(x) f(x)
#else
#define BAR(x) g(x)
#endif

In addition you do not have to give FOO a value, all you need to do is to #define it in source1.cpp

#define FOO
#include "header.h"

In source2.cpp I would also ensure that FOO is not defined (as a carry over from any other includes) by doing:

#ifdef FOO
#undef FOO
#endif
#include "header.h"

EDIT

I was a bit quick to say that the macro was wrong. As per this SO question What is the value of an undefined constant used in #if? (C++) the #if should work as given by the OP, as the value of FOO should decay to 0 when it is not defined.

However I think that using #ifdef provides more context as to what is actually desired.

Thus I suspect that the definition of FOO is sneaking in unexpectedly somewhere.

Community
  • 1
  • 1
Peter M
  • 7,309
  • 3
  • 50
  • 91
  • Isn't #define global to all files? – Ramy Al Zuhouri Jan 08 '13 at 13:23
  • @RamyAlZuhouri The scope of a `#define` is only the file in which it is included. – Peter M Jan 08 '13 at 13:29
  • Ok I got confused with .h files, +1. – Ramy Al Zuhouri Jan 08 '13 at 13:34
  • Thank you for the answer! I changed the code as you suggested, but it's still not working. I'll get back after some more tests. – Matti Jokipii Jan 08 '13 at 13:35
  • @RamyAlZuhouri BTW a better description of the scope is from the point that the `#define` is defined until the end if the file. – Peter M Jan 08 '13 at 13:35
  • 2
    @mjokipii It may be that the definition of `FOO` is sneaking into your file via an unexpected path from multiple `#include` statements. – Peter M Jan 08 '13 at 13:41
  • why do you think `#if` is incorrect? it's a valid preprocessor macro and would work in this example. – Andreas Grapentin Jan 08 '13 at 13:50
  • @AndreasGrapentin Yep you are right. However IMHO the intent is to use `#ifdef` and not `#if`. – Peter M Jan 08 '13 at 14:05
  • @Peter M This must be the case. I made a fresh case for testing and it's working, and for the record #if works as well as #ifdef. My original macro still isn't working. I'm going to look for the sneaking definition. The header in question is the first header file included in the source file, so that makes me wonder a bit though? – Matti Jokipii Jan 08 '13 at 14:06
  • @mjokipii I just got served by Andreas over the `#if` issue! – Peter M Jan 08 '13 at 14:09
0

For your case, The best way to differentiate based on macros is, using the toggle method:

#ifdef FOO
#define BAR(x) f(x)
#undef FOO
#else
#define BAR(x) g(x)
#endif

source1.cpp:

#define FOO
#include "header.h"

void a(int x) {
    BAR(x); // f(x)?
}

source2.cpp

#undef FOO
#include "header.h"  
void b(int x) {
    BAR(x); // g(x)?
}

For more control try this:

#ifdef FOO
  #if FOO == 1
  #define BAR(x) f(x)
  #undef FOO
  #elif FOO == 2
  #define BAR(x) g(x)
  #undef FOO
  #endif
#endif

And write like this:

source1.cpp:

#undef FOO
#define FOO 1
#include "header.h"

void a(int x) {
    BAR(x); // f(x)?
}

source2.cpp

#undef FOO
#define FOO 2
#include "header.h"  
void b(int x) {
    BAR(x); // g(x)?
}

There are several ways you can achieve, what you asked. Hope this helps.

askmish
  • 6,464
  • 23
  • 42
  • Thank you very much! This looks like the way to do this. It didn't solve the original problem though, please see my answer. – Matti Jokipii Jan 08 '13 at 15:15
0

The problem was that the header was after all indirectly included in the precompiled headers. XCode seems to include the precompiled headers automatically to every compilation unit, therefore only one version of the macro was available. The version precompiled was the one without the definition i.e. the #else-branch because no source files has been read at the time of the precompilation.

I will accept Peter M's answer as he came to the right conclusion about this.

The toggle method by askmish didn't help in my case, but that's the way i'll do this in the future, since that would have lead to the solution immediately.

Matti Jokipii
  • 561
  • 1
  • 6
  • 20