Pull to refresh

Comments 9

Все сущности, которые оказываются в анонимном пространстве имен, всегда имеют internal linkage


Эмм, я возможно ошибаюсь, но когда-то я уже с этим разбирался, и, нет, у них не internal linkage в чистом виде. Просто имя сущности оказывается при трансляции гарантированно уникальным и для него не находится соответствий при линковке. В этом смысле анонимные пространства имен не являются полным аналогом static-сущностей единицы трансляции (хотя в интернете часто именно так и пишут), но результат в общем оказывается один и тот же.
Так было до C++11, начиная с C++11 они должны иметь internal linkage:

en.cppreference.com/w/cpp/language/storage_duration

Но… тут не без сюрпризов. Вот здесь:

godbolt.org/z/yL2WUT

и clang и gcc линкуют к extern i только i, объявленную как static, если строчку с ее объявлением закомментировать, получим ошибку линковки. В то же время MSVC ведет себя «более по стандарту» — сразу ругается на ambiguous symbol i, и если закомментировать строку со static, то он линкует extern i к i из анонимного namespace, как и положено. Думаю, это баг, но поскольку такого рода вещи в реальном коде используются редко, то его никто особо не чинит :)
Так было до C++11, начиная с C++11 они должны иметь internal linkage

Пожалуй вы правы, наверное только так можно понять эту вставку здесь:
Even though names in an unnamed namespace may be declared with external linkage, they are never accessible from other translation units because their namespace name is unique. (until C++11)
Unnamed namespaces as well as all namespaces declared directly or indirectly within an unnamed namespace have internal linkage, which means that any name that is declared within an unnamed namespace has internal linkage. (since C++11)

Хотя все же точный механизм неочевиден.

Но… тут не без сюрпризов. Вот здесь:
godbolt.org/z/yL2WUT
и clang и gcc линкуют к extern i только i, объявленную как static, если строчку с ее объявлением закомментировать, получим ошибку линковки

Эм… Весь код расположен в одном модуле, стало быть оба определения модуле-локальных переменных i во-первых не должны транслироваться наружу (и тогда объявление extern int i вообще непонятно какой смысл имеет, причем его можно безболезненно удалить), а во-вторых они ambiguous по определению, компилятор обязан ругаться в соответствии со стандартом (все по той же ссылке выше). Это что за хрень такая?

extern int i в данном случае нужен всего-навсего для проверки linkage. Если internal linkage работает, то extern int i должен линковаться как к static int i, так и к i из анонимного namespace в пределах того же модуля. В MSVC это так и есть, а в gcc и clang internal linkage работает только со static, что стандарту не очень-то соответствует.

Я примерно так и понял, просто пример вышел очень контринтуитивный — обычно «extern» используется для указания того, что данная переменная определена (и память под нее выделена) в каком-то другом модуле, а тут мы пытаемся связаться с переменными в этом же модуле (при том, что они и так видны, будучи глобальными в рамках модуля). При этом, повторюсь, странно, что компилятор вообще не задает вопросов о том, к какой именно переменной мы обращаем.
Ну extern необязательно означает «в другом модуле», скорее «где-то», и это «где-то» вполне может быть и в текущем модуле. MSVC вот как раз и задает этот вопрос, для него неочевидно, к какой именно i этот extern привязать, а gcc и clang — нет, они привязывают ее только к static. Однако, если убрать extern, то и у них тоже появляются вопросы насчет ambigious.
Ну extern необязательно означает «в другом модуле», скорее «где-то», и это «где-то» вполне может быть и в текущем модуле


Ну вот это как раз и контринтуитивно для меня. Ни разу не использовал extern для обращения к переменным внутри того же модуля )))

gcc и clang — нет, они привязывают ее только к static. Однако, если убрать extern, то и у них тоже появляются вопросы насчет ambigious.


И это поведение в самом деле очень странное… Просто убиться веником.

Опечатка:
// other.cpp
struct Local {
static void foo() {
std::cout << "main "; // надо other
}
};

Спасибо за внимательность, поправили :)
Sign up to leave a comment.