TGViewer
C++95 C++95 @cxx95 · 1.51K subscribers
Post #38 590
#compiler

Прикладные linkage types в C++ 🔗

Стандартное добавление функции в C++ происходит так: в .h-файле пишется объявление функции (которое попадает в много translation unit), а в одном .cpp-файле пишется определение функции.

Чтобы определить функцию в .h-файле, чаще всего пишут спецификатор inline (это рекомендуемый путь), в несколько раз реже static.

Посмотрим, каким будет LLVM IR (компиляторное промежуточное представление C++-кода) для int sum1(), static int sum2(), inline int sum3(): ссылка на godbolt.

У LLVM IR есть интересный список linkage types для символов, типов много. Linkage type определяет, как ведет себя символ во время линковки в бинарник. (Символ - это функция или глобальная переменная)

▪️ У sum1 дефолтный linkage type external - возможно ровно 1 определение символа. Линковщик выдаст ошибку, если в программе будет 0 или >1 определения.

▪️ У sum2 linkage type internal - символ доступен только из того translation unit, где определен. Если в процессе линковки попадется одноименный символ, то линковщик просто переименует sum2, чтобы не было коллизии.

▪️ У sum3 linkage type linkonce_odr. Это типичный weak symbol, как и некоторые другие типы (linkonce, weak).
В программе может быть несколько weak-определений одного и того же символа.
Если все определения символа являются weak, то линковщик берет рандомное определение.
Если какое-то из определений символа является strong (как у sum1), то линковщик берет strong-определение.

В чем отличие linkonce от linkonce_odr?
▪️ В общем случае weak-определения могут быть разными, поэтому компилятор не имеет права заинлайнить вызов weak-функции (после линковки у функции может оказаться совсем другое определение)
▪️ Но Стандарт С++ требует от программиста обеспечить, чтобы inline-функции имели идентичное определение (это естественным образом достигается, если определение находится в .h-файле)
▪️ Поэтому компилятор имеет право заинлайнить вызов метода sum3 - программа от этого сломаться не сможет

Скомпилируем объектный файл
> clang++ -c link.cpp
На Linux получим объектный файл формата ELF. Используем утилиту readelf для чтения таблицы символов. Чтобы вывести исходные имена методов (не mangled-имена), используем утилиту c++filt:
> readelf -s link.o | c++filt

Получим такой вывод (опустил другие символы):
Symbol table '.symtab' contains 21 entries:
Num: Value Size Type Bind Vis Ndx Name
6: 00000000000000c0 18 FUNC LOCAL DEFAULT 2 sum2(int, int)
14: 0000000000000000 18 FUNC GLOBAL DEFAULT 2 sum1(int, int)
20: 0000000000000000 18 FUNC WEAK DEFAULT 7 sum3(int, int)

В общем случае выгоднее использовать inline-методы, чем static-методы! Потому что так меньше загрязняется бинарник, и все статические переменные внутри функции живут в количестве 1 штуки, а не в N штук:
inline int* get_address() {
// `dummy` займет sizeof(int) памяти, а со static-методом было бы N*sizeof(int)
static int dummy;
// inline-метод - возвращает один и тот же указатель
// static-метод - уникальный для каждого translation unit
return &dummy;
}
  • 👍 9
More from @cxx95
  1. Sep 21, 2026#offtop Великое Мидревью 💼 В последнее время темы про C++ накапливаются медленно, и то та…
  2. Jun 17, 2026#jostik Обзор жостиков C++ 💼 (номер 5️⃣) В последние несколько месяцев совсем ничего не п…
  3. Jun 17, 2026document post
  4. Jan 7, 2026#compiler #ai На фото из марта 2024 - мерч с работы, это кофта и набор нашивок, которые мо…
  5. Jan 7, 2026document post
  6. Aug 18, 2025#books Текст в окружности - первые слова в опере (услышать) 🎤 📕 Обзор на книгу про памят…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →