Question

I've written some C++ code for an embedded system which works like a charm. The current task is to emulate the behaviour of this device on a PC. Some of the code has to be ported: For a first test I'm using mingw (g++) while the Embedded system is an STM32 and uses the KEIL µVision toolchain.

I've run into a problem that is not really related to functional behaviour rather than a compiler specific weirdness. I have 2 classes defined in an anonymous namespace because they are included throughout the whole project. Now on the embedded device this compiles and runs without a problem. g++ complains about an undefined reference!

When I remove the anonymous namespace arround the class it compiles and runs! But why? Here is some example code that reproduces the situation: main.cpp:

#include "notmain.h"
#include "theclass.h"

A *ourA=NULL;

int main()
{
    theA = new A();
    theA->dostuff(1024);
    sunshine sun;
    sun.Init();
}

notmain.cpp:

#include "notmain.h"
#include "theclass.h"

void sunshine::Init()
{
    theA->dostuff(127);
}

notmain.h:

#ifndef NOTMAIN_H_
#define NOTMAIN_H_
class sunshine
{
public:
    void Init();
};
#endif

theclass.h:

#ifndef THECLASS_H_
#define THECLASS_H_
#include <stdio.h>
#define theA ourA
namespace
{
    class A
    {
    public:
        void dostuff(int b)
        {
            a = b;
            printf("Hello: %d\n",a);
        }
    private:
        int a;
    };
}
extern A *ourA;
#endif

Compiler/Linker Output: 09:09:57 ** Incremental Build of configuration Debug for project Testo ** Info: Internal Builder is used for build g++ -O0 -g3 -Wall -c -fmessage-length=0 -o main.o "..\main.cpp" g++ -O0 -g3 -Wall -c -fmessage-length=0 -o notmain.o "..\notmain.cpp" g++ -o Testo.exe notmain.o main.o notmain.o: In function ZN8sunshine4InitEv': D:\Projekte\Testo\Debug/../notmain.cpp:6: undefined reference toourA' collect2.exe: error: ld returned 1 exit status

09:09:57 Build Finished (took 702ms)

Removing that namespace fixes the problem but why does it compile, link, work in KEIL? Can anyone explain this to me?

Was it helpful?

Solution

I would suggest that that is an abuse of the anonymous namespace feature. It does exactly the opposite of what you are trying to achieve.

Anonymous namespaces are used to localise a definition to a single translation unit. If you place one in a header file, then include that header in multiple translation units, that will result in multiple independent definitions in your code.

What is happening here VC++ is that a global ourA has been instantiated as a pointer to one local definition of A defined in main.cpp, then later that local definition is no longer visible but is distinct from the currently visible local version in notmain.cpp. The name mangling of ZN8sunshine4InitEv distinguishes between independent definitions, but name mangling is compiler defined, and I guess ARM's RealView compiler (used by uVision) has a different scheme that fails to spot this error.

It is unclear in fact what the result if this error is in RealView, but it cannot be correct or at least well defined.

RealView is in fact rather poor at issuing warnings that other compilers do normally, and is somewhat permissive when it comes to undefined behaviour I have found. It is always worth using another toolchain such as MinGW/GCC with -Werror -Wall or using a static analysis tool to clean up your code.

To solve this problem you should use an explicitly named namespace, or no namespace at all.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top