Conditional compilation bug or feature ?

Conditional compilation bug or feature ?

Hi,

I have a software that has 2 versions of an implemented algorithm, so it used different versions of the same class (in my case its SSE vs AVX, but really, it's not relevant) in 2 different compiler units, and suprisingly the linker take the initiative of taking an arbitrary one.

Is it a bug (that I reproduced as well in Microsoft and GCC compiler) or a feature (if that so can someone help me finding where this behavior is specified) ?

Here is how to reproduce the problem:

toto.h

#include <stdio.h>

#ifdef FLAG
class foo
{
public:
    void bar()
    {
        printf("FLAG\n");
    }
};
#else
class foo
{
public:
    void bar()
    {
        printf("NO FLAG\n");
    }
};
#endif

#ifdef FLAG
void call_foobar_FLAG()
#else
void call_foobar_NOFLAG()
#endif
{
    foo().bar();
}

toto_flag.cpp

#define FLAG
#include "toto.h"

toto_noflag.cpp

#include "toto.h"

main.cpp

void call_foobar_FLAG();
void call_foobar_NOFLAG();

int main(int argc, char ** argv)
{
    call_foobar_FLAG();
    call_foobar_NOFLAG();
}

We should expect as output

FLAG
NO FLAG

But we get

FLAG
FLAG

or

NO FLAG
NO FLAG

depending in which order object are linked...

6 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

FLAG may be #defined in (by) stdio.h

Also, you may have enabled pre-compiled headers.

Jim Dempsey

Ok rename FLAG with RANDOM34834626723, <stdio.h> is here just for the printf to work in this reproductible example.

You would have the same result.

And no i did not enabled precompiled headers (nor optimizations, nor /Qip or /Qipo or global optimization or anything that could do some "magic" across objs)

Actually

gcc main.cpp toto_noflag.cpp toto_flag.cpp && a.exe

silently outputs NO FLAG twice

gcc main.cpp toto_flag.cpp toto_noflag.cpp && a.exe

silently outputs FLAG twice

So it's even not specific to Intel if this is a bug.

 

You are violating the ODR (One Definition Rule) so the implementation is allowed to do anything it wants.

See:

http://en.wikipedia.org/wiki/One_Definition_Rule

and section 3.2 of the C++ standard.

 

Judy

 

 

Thank you Judith, I understand now why what I did was completely non-standard.

I solved my issues by enclosing it in anonymous namespaces, which seems the proper way to do.

Hi Judith,

This ODR raises another problem.

If I have a project mixing a file compiled with /QxAVX and another one with any other architecture selection (for instance /QxSSE), if both for instance use a STL class like std::basic_string. Then in both translation unit will share the same std::basic_string and have AVX code into it.

And unfortunately in Intel Compiler there is no flag to activate AVX (in the way that the instrinsic are translated into VEX instructions) without having these injection of AVX code where its not needed (and which prevents the use of classes, that I cannot put in an anonymous namespace, between compilands targeted for different architectures).

Best Regards,

Emmanuel

Leave a Comment

Please sign in to add a comment. Not a member? Join today