0

Для того, чтобы глобальные переменные/функции имели внутреннее связывание (internal linkage), начиная с C++11 достаточно поместить их определение в безымянное пространство имён (unnamed namespace):

namespace {
    int foo() {
        return 42;
    }
}

До C++11 необходимо было указывать ключевое слово static:

static int foo() {
    return 42;
};

Услышал мнение, что с технической точки зрения при объявлении глобальных переменных/функций в безымянных пространствах имён всё равно лучше дописывать ключевое слово static, т.к. это ускоряет процесс линковки:

namespace {
    static int foo() {
        return 42;
    }
}

Насколько это правда?

magrif
  • 2,789
  • Во-первых, сомнительно, во-вторых — это (время линковки) так важно?! – Harry Jan 02 '22 at 10:06
  • поэтому и спрашиваю. А почему не важно? – magrif Jan 02 '22 at 10:08
  • 1
    Обычно линковка проходит быстро, поэтому об ее ускорении никто не задумывается. А функции при возможности лучше в самом деле делать static, это повышает инкапсуляцию, сразу говорит читателю кода, что данная функция имеет смысл только в этом файле (единице компиляции) – avp Jan 02 '22 at 10:14
  • @avp повышает инкапсуляцию тут в смысле повышения читабельности кода, не более? – magrif Jan 02 '22 at 10:24
  • 1
    @magrif, все эти ООП-шные штучки нужны тоолько для улучшения пониманя кода человеком (железу, которое реально работает, они до лампочки...) – avp Jan 02 '22 at 10:27
  • @avp "Обычно линковка проходит быстро, поэтому об ее ускорении никто не задумывается." С другой стороны, развелось много линковщиков, каждый из которых рекламируется как более быстрый, чем предыдущий: LD, Gold, LLD, Mold... И плюс майкрософтовский link.exe. – HolyBlackCat Jan 02 '22 at 13:16

2 Answers2

2

С точки зрения редактора связей (линкера) anon. namespace и static абсолютно эквивалентны (с точностью до манглирования имён):

$ cat tmp1.cc
namespace { void foo() {} }
$ g++ -c tmp1.cc && readelf -sW tmp1.o | g foo
     5: 0000000000000000    11 FUNC    LOCAL  DEFAULT    1 _ZN12_GLOBAL__N_13fooEv
$ cat tmp2.cc
static void foo() {}
$ g++ -c tmp2.cc && readelf -sW tmp2.o | g foo
     5: 0000000000000000    11 FUNC    LOCAL  DEFAULT    1 _ZL3foov
$ cat tmp3.cc
namespace { static void foo() {} }
$ g++ -c tmp3.cc && readelf -sW tmp3.o | g foo
     5: 0000000000000000    11 FUNC    LOCAL  DEFAULT    1 _ZN12_GLOBAL__N_1L3fooEv

Как можно видеть компилятор использовал символы одинакового типа (LOCAL DEFAULT) в порождённых объектных файлах, а значит редактор связей в процессе линковки будет обрабатывать их одинаковым образом (и соответственно время работы не поменяется).

yugr
  • 148
  • 1
    Не ответ на вопрос. Это результат, а интересует есть ли разница во времени получения этого результата для представленных вариантов. – magrif Jan 02 '22 at 13:46
  • 1
    @magrif это не результат, а скорее промежуточная стадия. Я дописал вывод (видимо из-за профдеформации мне он изначально показался очевидным). – yugr Jan 02 '22 at 14:47
1

Во-первых, с точки зрения компилятора функция в анонимном пространстве имен вовсе не эквивалентна такой же функции, но с модификатором static, как то утверждается в другом ответе. Основное отличие - функция в анонимном пространстве имен не учитывается при выполнении ADL. Так что после простой замены static на анонимное пространство имен код может изменить поведение или даже вообще перестать работать, так что тут надо быть аккуратным.

Во-вторых, какай вариант быстрее по скорости последующей линковки - на самом деле не так уж важно, так вклад этих сущностей в общее время линковки не может быть существенным, если только вся программа не состоит из тысяч статических функций и глобальных переменных.

В-третьих, для того чтобы реально ускорить процесс линковки необходимо сокращать число единиц трансляций. В идеале перейти на сборку SCU, где всё реализовано в заголовочных файлах. А вот тут нагромождения глобальных переменных и функций со статическим связыванием могут сыграть с вами злую шутку, так как придется разбираться с коллизиями и избавляться от них.

yugr
  • 148
user7860670
  • 29,796
  • "с точки зрения компилятора функция в анонимном пространстве имен вовсе не эквивалентна такой же функции ... Основное отличие - функция в анонимном пространстве имен не учитывается при выполнении ADL" - погодите, вы про статические методы? В вопросе речь явно идёт про статическую функцию (не являющуюся членом класса) и для них это утверждение несправедливо. – yugr Jan 03 '22 at 14:55
  • Нет, я про статическую функцию, которая не является членом класса. – user7860670 Jan 03 '22 at 14:55
  • "В идеале перейти на сборку SCU" - вы про Unity Build? Довольно спорное утверждение, т.к. за сокращение времени линковки скорее всего придётся заплатить резким ростом времени компиляции (сравните как вырастает время сборки при включении LTO). – yugr Jan 03 '22 at 14:56
  • "Нет, я про статическую функцию" - может тогда приведёте пример/пруфлинк для сомневаюющихся? – yugr Jan 03 '22 at 14:57
  • Нет, я не про Unity build. Точнее не совсем про него. И нет, unity и, тем более, полноценное SCU как раз направлено на сокращение времени сборки. см https://ru.stackoverflow.com/questions/1334642/%d0%a0%d0%b5%d0%b0%d0%bb%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d1%8f-%d0%b2-%d1%85%d0%b5%d0%b4%d0%b5%d1%80-h-%d1%84%d0%b0%d0%b9%d0%bb%d0%b5-%d0%b8%d0%bb%d0%b8-%d1%80%d0%b0%d0%b7%d0%b4%d0%b5%d0%bb%d1%91%d0%bd%d0%bd%d0%b0%d1%8f-%d0%bd%d0%b0-h-%d0%b8-cpp/1334666#1334666 – user7860670 Jan 03 '22 at 14:59
  • "какой вариант быстрее по скорости последующей линковки - на самом деле не так уж важно, так вклад этих сущностей в общее время линковки не может быть существенны" - для рантайм-линковки он достаточно существенен, чтобы имело смысл разрабатывать специальный тул для уменьшения релокаций (Prelink) ¯\_(ツ)_/¯ – yugr Jan 03 '22 at 14:59
  • Нет, рантайм линковка тут вообще ни при чем. К сущностями со внутренним связыванием и со встраиваемым она же не работает. – user7860670 Jan 03 '22 at 15:02
  • "Нет, я не про Unity build" - может тогда приведёте ссылку? "SCU build" не гуглится... – yugr Jan 03 '22 at 15:02
  • "К сущностями со внутренним связыванием и со встраиваемым она же не работает" - конечно, поэтому они очень полезны и их надо использовать даже в Unity builds (ваше утверждение "нагромождения ... функций со статическим связыванием" вроде как утверждает обратное). – yugr Jan 03 '22 at 15:03
  • Я же уже привел, и в том ответе даже ссылка на википедию для ликбеза есть. – user7860670 Jan 03 '22 at 15:04
  • "И нет, unity и, тем более, полноценное SCU как раз направлено на сокращение времени сборки." - я нежно люблю unity builds, но это утверждение как мимимум спорно (см. хотя бы вики, там про OOM и параллелизм). Я как компиляторщик добавлю что многие алгоритмы начинают "взрываться" с ростом объёма входного файла. – yugr Jan 03 '22 at 15:09
  • Утверждение про "нагромождения ... функций со статическим связыванием" утверждает, что они эти функции (да и глобальные переменные) создают проблемы при SCU, а не про линковку. – user7860670 Jan 03 '22 at 15:16
  • А SCU вовсе не приводит к какому-то радикальному росту объема входного файла. Как раз наоборот, в целом объем обрабатываемых данных радикально снижается. Это второй пункт в том моем ответе. Кроме того, оно никак не препятствует параллелизму при сборке нескольких проектов за счет. – user7860670 Jan 03 '22 at 15:24
  • "они эти функции создают проблемы при SCU, а не про линковку" - я вас понял, да, это действительно проблема для unity. Мой поинт был в том, что если уж код использует глобальные переменные, то с точки зрения ускорения линковки (как статической, так и динамической) static "лучше" обычных глобалов. – yugr Jan 03 '22 at 15:32
  • "в целом объем обрабатываемых данных радикально снижается" - не совсем так, на этапе мидленда сильно вырастают обрабатываемые структуры данных типа call graph, вырастают размеры функций за счёт более агрессивного межмодульного инлайнинга и клонирования. Добавьте к этому сверхлинейное время работы многих оптимизационных алгоритмов в компиляторе и получите простой способ получить экспоненциальный рост. В частности поэтому для unity-сборок и применятют шардинг. – yugr Jan 03 '22 at 15:36