Yochai Timmer
Yochai Timmer

Reputation: 49251

Compiling same header with different compilation flag in different compilation units

I've encountered a strange problem that kind of breaks what I understand about a compilation unit's encapsulation.

In a nutshell I have a common inlined function that I get from a header.
I include that into 2 different .cpp files, with a different #define macros.
But I end up getting the same implementation in bot compilation units.

Common.h:

#include <iostream>

inline void printA()
{
#ifdef YES
    std::cout << " yes" << std::endl;
#else
    std::cout << " no" << std::endl;
#endif
}

File1.h:

void print1();

File1.cpp:

#define YES
#include "Common.h"
#include "File1.h"

void print1()
{
    printA();
}

File2.h:

void print2();

File2.cpp

#include "Common.h"
#include "File2.h"
void print2()
{
    printA();
}

main.cpp:

#include "File1.h"
#include "File2.h"

int main(int argc, char* argv[])
{

    print1();
    print2();

    return 0;
}

The output to this example is:

yes
yes

I would expect it to be:

yes
no

So, why is the same implementation taken in both compilation units ?
The common function is even inlined....

How can I get my "expected" result?

And, why is the "yes" implementation chosen ? Just a matter of compilation order?

BTW, I get the same results on GCC 4.8 and VS2012

Upvotes: 2

Views: 249

Answers (1)

Bo Persson
Bo Persson

Reputation: 92271

The standard (here N4527) says in 3.2 One definition rule/6

There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then (6.1)

— each definition of D shall consist of the same sequence of tokens; and

...

If the definitions of D satisfy all these requirements, then the behavior is as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.

So replacing "yes" with "no" is an ODR-violation, causing undefined behavior.

For the result of getting "yes" I can guess that the compiler picks one function at random, as they have to be identical.

On the other hand, if you made the function static, you would have different local functions in each translation unit.

Upvotes: 3

Related Questions