Стандарт, по-видимому, подразумевает, что не существует ограничений на количество определений переменной, если она не УСО используемый (§3.2 / 3):
Каждая программа должна содержать ровно одно определение каждой не встроенной функции или переменной, которая используется в этой программе в виде odr; Диагностика не требуется.
Это говорит о том, что ни одна переменная не может быть определена несколько раз в единице перевода (§3.2 / 1):
Ни одна единица перевода не должна содержать более одного определения любой переменной, функции, типа класса, типа перечисления или шаблона.
Но я не могу найти ограничение для неиспользуемых переменных во всей программе. Так почему я не могу скомпилировать что-то вроде следующего:
// other.cpp
int x;
// main.cpp
int x;
int main() {}
Компилируя и связывая эти файлы с g ++ 4.6.3, я получаю ошибку компоновщика для multiple definition of 'x'
, Если честно, я ожидаю этого, но так как x
нигде не используется odr (насколько я могу судить), я не вижу, как стандарт ограничивает это. Или это неопределенное поведение?
Ваша программа нарушает правила связи. C ++ 11 §3.5 [basic.link] / 9 гласит:
Два одинаковых имени, объявленные в разных областях, должны обозначать одно и то же.
переменная, функция, тип, перечислитель, шаблон или пространство имен, если
оба имени имеют внешнюю связь, иначе оба имени имеют внутреннюю связь и объявляются в одной и той же единице перевода; а также
оба имени относятся к членам одного и того же пространства имен или к членам, не по наследству, одного и того же класса; а также
когда оба имени обозначают функции, списки параметров-типов функций идентичны; а также
когда оба имени обозначают шаблоны функций, подписи одинаковы.
(Я привел полный абзац для справки. Вторые два пункта здесь не применимы.)
В вашей программе есть два имени x
, которые одинаковы. Они объявляются в разных областях (в этом случае они объявляются в разных единицах перевода). Оба имени имеют внешнюю связь, и оба имени относятся к членам одного и того же пространства имен (глобального пространства имен).
Эти два имени не делайте обозначим одну и ту же переменную. Декларация int x;
определяет переменную. Поскольку в программе есть два таких определения, в программе есть две переменные. Имя «х» в одной единице перевода обозначает одну из этих переменных; имя «х» в другой единице перевода обозначает другой. Поэтому программа плохо сформирована.
Вы правы, что стандарт виноват в этом отношении. У меня есть ощущение, что этот случай попадает в промежуток между 3.2p1 (самое большее одно определение на единицу перевода, как в вашем вопросе) и 3.2p6 (который описывает, как классы, перечисления, встроенные функции и различные шаблоны могут иметь дубликаты определений по всему переводческие единицы).
Для сравнения, в C 6.9p5 требуется (мой акцент):
Внешнее определение — это внешнее объявление, которое также является определением функции.
(кроме встроенного определения) или объект. Если идентификатор, объявленный с внешней связью, используется в выражении (кроме как как часть операндаsizeof
или же_Alignof
оператор, результатом которого является целочисленная константа), где-то во всей программе должно быть ровно одно внешнее определение для идентификатора; в противном случае должно быть не более одного.
Если стандарт ничего не говорит об определениях неиспользуемых переменных, то вы не можете подразумевать, что их может быть несколько:
Неопределенное поведение может также ожидаться, когда этот Международный
Стандарт опускает описание любого явного определения
поведение.
Таким образом, он может хорошо скомпилироваться и работать или может остановиться во время перевода с сообщением об ошибке или может привести к сбою во время выполнения и т.д.
РЕДАКТИРОВАТЬ: См. Джеймс Макнеллис ответ стандарт действительно на самом деле есть правила об этом.
Нет ошибки в компиляции, ошибка в его связи. По умолчанию ваша глобальная переменная или функции общедоступны для других файлов (есть extern
хранения), поэтому в конце, когда компоновщик хочет связать ваш код, он видит два определения для x
и он не может выбрать один из них, поэтому, если вы не используете x
из main.cpp
в other.cpp
и наоборот делают их статичными (это означает, что они видны только файлу, который их содержит)
// other.cpp
static int x;
// main.cpp
static int x;