Если я не использую переменную odr, могу ли я иметь несколько ее определений в единицах перевода?

Стандарт, по-видимому, подразумевает, что не существует ограничений на количество определений переменной, если она не УСО используемый (§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 (насколько я могу судить), я не вижу, как стандарт ограничивает это. Или это неопределенное поведение?

14

Решение

Ваша программа нарушает правила связи. C ++ 11 §3.5 [basic.link] / 9 гласит:

Два одинаковых имени, объявленные в разных областях, должны обозначать одно и то же.
переменная, функция, тип, перечислитель, шаблон или пространство имен, если

  • оба имени имеют внешнюю связь, иначе оба имени имеют внутреннюю связь и объявляются в одной и той же единице перевода; а также

  • оба имени относятся к членам одного и того же пространства имен или к членам, не по наследству, одного и того же класса; а также

  • когда оба имени обозначают функции, списки параметров-типов функций идентичны; а также

  • когда оба имени обозначают шаблоны функций, подписи одинаковы.

(Я привел полный абзац для справки. Вторые два пункта здесь не применимы.)

В вашей программе есть два имени x, которые одинаковы. Они объявляются в разных областях (в этом случае они объявляются в разных единицах перевода). Оба имени имеют внешнюю связь, и оба имени относятся к членам одного и того же пространства имен (глобального пространства имен).

Эти два имени не делайте обозначим одну и ту же переменную. Декларация int x; определяет переменную. Поскольку в программе есть два таких определения, в программе есть две переменные. Имя «х» в одной единице перевода обозначает одну из этих переменных; имя «х» в другой единице перевода обозначает другой. Поэтому программа плохо сформирована.

11

Другие решения

Вы правы, что стандарт виноват в этом отношении. У меня есть ощущение, что этот случай попадает в промежуток между 3.2p1 (самое большее одно определение на единицу перевода, как в вашем вопросе) и 3.2p6 (который описывает, как классы, перечисления, встроенные функции и различные шаблоны могут иметь дубликаты определений по всему переводческие единицы).

Для сравнения, в C 6.9p5 требуется (мой акцент):

Внешнее определение — это внешнее объявление, которое также является определением функции.
(кроме встроенного определения) или объект. Если идентификатор, объявленный с внешней связью, используется в выражении (кроме как как часть операнда sizeof или же _Alignof оператор, результатом которого является целочисленная константа), где-то во всей программе должно быть ровно одно внешнее определение для идентификатора; в противном случае должно быть не более одного.

5

Если стандарт ничего не говорит об определениях неиспользуемых переменных, то вы не можете подразумевать, что их может быть несколько:

Неопределенное поведение может также ожидаться, когда этот Международный
Стандарт опускает описание любого явного определения
поведение.

Таким образом, он может хорошо скомпилироваться и работать или может остановиться во время перевода с сообщением об ошибке или может привести к сбою во время выполнения и т.д.

РЕДАКТИРОВАТЬ: См. Джеймс Макнеллис ответ стандарт действительно на самом деле есть правила об этом.

1

Нет ошибки в компиляции, ошибка в его связи. По умолчанию ваша глобальная переменная или функции общедоступны для других файлов (есть extern хранения), поэтому в конце, когда компоновщик хочет связать ваш код, он видит два определения для x и он не может выбрать один из них, поэтому, если вы не используете x из main.cpp в other.cpp и наоборот делают их статичными (это означает, что они видны только файлу, который их содержит)

// other.cpp
static int x;

// main.cpp
static int x;
0
По вопросам рекламы [email protected]