Этот ответ показывает, как правила C 2018 исключают использование одного и того же идентификатора в качестве члена двух различных перечислений. Это мнение юриста по языку, призванное показать, как это требование вытекает из языка стандарта.
6.2.3, «Пространства имен идентификаторов», говорит нам:
Если в какой-либо точке единицы перевода видно более одного объявления определенного идентификатора, синтаксический контекст устраняет неоднозначность использования, которое относится к разным объектам. Таким образом, существуют отдельные пространства имен для различных категорий идентификаторов, а именно:
...
- все остальные идентификаторы, называемые обычные идентификаторы (объявленные в обычных деклараторах или в качестве констант перечисления).
Таким образом, все константы перечислителя и обычные деклараторы существуют в одном пространстве имен. (Пространства имен, пропущенные выше, предназначены для меток [для goto
операторов]; тегов структур, объединений и перечислений [имя после struct
, как в struct foo
] и членов структур или союзов [каждый имеет свое пространство имен]).
6.7, «Объявления», в параграфе 5 говорится, что:
A определение идентификатора является объявлением для этого идентификатора, которое:
...
для константы перечисления является (единственным) объявлением идентификатора;
...
Таким образом, стандарт указывает, что существует только одно определение константы перечисления. Кроме того, 6.2.1, «Области идентификаторов», говорит нам в пункте 1:
Идентификатор может обозначать объект; функция; тег или член структуры, объединения или перечисления; имя определения типа; название ярлыка; имя макроса; или параметр макроса. Один и тот же идентификатор может обозначать разные объекты в разных точках программы. Член перечисления называется константа перечисления .
Обратите внимание, что это говорит о том, что если foo
идентифицирует константу перечисления, то она идентифицирует члена перечисления - это конкретный член конкретного перечисления. Он не может идентифицировать как участника enum A
, так и участника enum B
. Поэтому, если бы у нас был код:
enum A { foo = 1 };
enum B { foo = 1 };
в точке, где foo
появляется во второй раз, это идентификатор для foo
в enum A
, и, следовательно, он не может быть членом enum B
.
(Предложение об идентификаторе, обозначающем разные сущности в разных точках, вводит понятие scope . Дальнейшие параграфы в этом пункте объясняют понятие области действия и четырех видов области действия: функция, файл, блок и прототип функции. Они не влияют на приведенный выше анализ, поскольку приведенный выше код находится в одной области видимости.)