#новичкам
В С нет перегрузки функций, поэтому там люди вынуждены каким-то образом руками разделять имена функций.
Вместо
void print(int x);
void print(float x);
Там пишут:
void print_int(int x);
void print_float(float x);
Плюс линкеры работают с именами символов. А имя функции в С не включает в себя параметры. Поэтому во всей программе не может быть двух функций с одинаковыми именами. Линкер их банально не различит и выдаст ошибку множественного определения.
А в С++ была перегрузка и надо было каким-то образом плюсовые перегруженные функции превращать в неперегруженные сишные при трансляции кода. Для этого было придумано декорирование имен или name mangling.
Самый простой способ - добавлять к конце функции ее параметры в закодированном виде: ИмяФункции_ТипыПараметров:
void draw(int x, int y);
void draw(double x, double y);
// Cfront mangling:
draw_i_i // draw(int, int)
draw_d_d // draw(double, double)
Так как у нас не может быть двух перегрузок с разными возвращаемыми значениями, то кодирование типа возврата не нужно.
Но это самое базовое представление о декорировании имен. Давайте посмотрим, что еще может влиять на итоговое имя функции:
👉🏿 2 разных класса могут иметь методы с одинаковым названием. Так как при трансляции в С это были просто свободные функции, манглинг должен учитывать и имя класса:
void Circle::paint(Color c);
void Square::paint();
Rectangle::~Rectangle();
Shape::~Shape();
// transform into
void Circle_paint_Color(struct Circle* this, struct Color c);
void Square_paint(struct Square* this);
void Rectangle_dtor(struct Rectangle* this);
void Shape_dtor(struct Shape* this);
👉🏿 Есть же еще и пространства имен. Они помогают разграничить скоуп существования имен. И названия пространства имен тоже манглировались в имена функций:
namespace Graphics {
class Canvas {
void clear();
};
}
// transform into
void Graphics_Canvas_clear(struct Canvas* this)👉🏿 В С++ когда-то появились шаблоны. Шаблон всегда инстанцируется с каким-то типом. И чтобы различать эти инстанциации, Cfront манглировал типы шаблонных параметров в полное имя типа:
template<typename T>
class Stack {
void push(T value);
};
Stack<int> stack;
// transforms into
Stack_int_push_i(int value);
Конкретные преобразованные имена из поста могут быть не такими, какими их генерировал Cfront, но главное уловить идею.
В современных компиляторах тоже делается манглинг имен, чтобы линкер не ругался на одинаковые символы:
void Circle::rotate(int);
// transforms into
_ZN6Circle6rotateEi
// Разбор:
_Z - префикс C++
N - вложенное имя
6Circle - длина=6, "Circle"
6rotate - длина=6, "rotate"
E - конец аргументов
i - тип int
Шаблоны, неймспейсы, noexcept и const квалификаторы - все вшивается в имя символа.
Вы также можете вручную управлять манглингом: включать и выключать его:
extern "C" void c_function(); // Без манглинга: _c_function
extern "C++" void cpp_function(); // С манглингом: _Z10cpp_functionv
Это нужно для совместимости ABI интерфейсов, предоставляемых библиотеками.
Поэтому декорирование имен живее всех живых и повсеместно используется в современных компиляторах.
Have a legacy. Stay cool
#cppcore #goodoldc #compiler