Это для MSVC.
Пространство имен само по себе не является искаженным, но имя пространства имен включается в имя функции (или объекта), когда происходит искажение имени.Этот процесс недокументирован, но описан здесь .
Отвечая на ваши конкретные вопросы, прыгая вокруг:
1) Стандартного поведения в отношении искажения имени не существует.Стандарт фактически говорит о том, что реализации предоставляют C-совместимое связывание для extern "C"
конструкций:
7.5.3 [Спецификации связывания]
Каждая реализация должна предусматривать связь с функцияминаписанный на языке программирования C, "C", и связь с функциями C ++, "C ++".[Пример:
complex sqrt(complex); // C + + linkage by default
extern "C" { double sqrt(double); // C linkage }
- конечный пример]
В конечном итоге это означает, что, поскольку C не имеет понятия namespace
s, если extern "C"
функций или объектов в пространствах имен, ваши экспортированные имена потеряют квалификацию пространства имен.Это приводит к ...
3) Да, у вас может быть проблема со связью.Попробуйте это:
main.h
#ifndef MAIN_API
# define MAIN_API __declspec(dllexport)
#endif
namespace x
{
extern "C" MAIN_API void foo();
};
namespace y
{
extern "C" MAIN_API void foo();
};
main.cpp
#include <cstdlib>
#include <iostream>
using namespace std;
#define MAIN_API __declspec(dllexport)
#include "main.h"
void x::foo()
{
cout << "x::foo()\n";
}
void y::foo()
{
cout << "y::foo()\n";
}
int main()
{
}
Это выдаст ошибку компоновщика, так как extern "C"
-эд версия x::foo()
и y::foo()
потеряли свою идентификацию пространства имен, поэтому в итоге они получили одно и то же имя: foo()
2) Лучшие практики в этом отношении.Если вы должны экспортировать C-ABI для функций в пространствах имен, вы должны быть осторожны, чтобы имена, которые вы в конечном итоге экспортировали, не совпадали.В некоторой степени это побеждает цель использования namespace
в первую очередь.Но вы можете сделать что-то вроде этого:
#ifndef MAIN_API
# define MAIN_API __declspec(dllexport)
#endif
namespace x
{
extern "C" MAIN_API void x_foo();
};
namespace y
{
extern "C" MAIN_API void y_foo();
};