Я написал код на C ++ для встроенной системы, которая работает как шарм. Текущая задача — эмулировать поведение этого устройства на ПК. Часть кода должна быть портирована: для первого теста я использую mingw (g ++), в то время как встроенная система является STM32 и использует цепочку инструментов KEIL µVision.
Я столкнулся с проблемой, которая на самом деле не связана с функциональным поведением, а не с особенностями компилятора. У меня есть 2 класса, определенных в анонимном пространстве имен, потому что они включены во весь проект. Теперь на встроенном устройстве это компилируется и запускается без проблем. G ++ жалуется на неопределенную ссылку!
Когда я удаляю анонимное пространство имен вокруг класса, он компилируется и запускается! Но почему? Вот пример кода, который воспроизводит ситуацию:
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
Выход компилятора / компоновщика:
9:09:57 ** Инкрементная сборка конфигурации Debug для проекта Testo **
Информация: Внутренний Строитель используется для сборки
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: в функции ZN8sunshine4InitEv':
Ора»
D:\Projekte\Testo\Debug/../notmain.cpp:6: undefined reference to
collect2.exe: ошибка: ld вернул 1 состояние выхода
09:09:57 Build Finished (took 702ms)
Удаление этого пространства имен решает проблему, но почему оно компилируется, связывается, работает в KEIL? Кто-нибудь может мне это объяснить?
Я бы предположил, что это злоупотребление анонимным пространством имен. Это в точности противоположно тому, чего вы пытаетесь достичь.
Анонимные пространства имен используются для локализации определения в одной единице перевода. Если вы поместите один в файл заголовка, то включите этот заголовок в несколько единиц перевода, что приведет к нескольким независимым определениям в вашем коде.
Что здесь происходит, VC ++ является то, что глобальный ourA
был создан как указатель на одно локальное определение A
определяется в main.cpp, а затем местный определение больше не отображается, но отличается от текущей видимой локальной версии в notmain.cpp. Название искажения ZN8sunshine4InitEv
различает независимые определения, но искажение имени определяется компилятором, и я предполагаю, что компилятор RealView ARM (используемый uVision) имеет другую схему, которая не может обнаружить эту ошибку.
На самом деле неясно, каков будет результат, если эта ошибка присутствует в RealView, но она не может быть правильной или, по крайней мере, четко определенной.
RealView на самом деле довольно слаб в выдаче предупреждений, которые обычно делают другие компиляторы, и является несколько допустимым, когда дело доходит до неопределенного поведения, которое я обнаружил. Всегда стоит использовать другой набор инструментов, например MinGW / GCC с -Werror -Wall, или использовать инструмент статического анализа для очистки вашего кода.
Чтобы решить эту проблему, вы должны использовать пространство имен с явным именем или вообще не использовать пространство имен.
Других решений пока нет …