Область перечисления - PullRequest
       1

Область перечисления

9 голосов
/ 09 декабря 2011

Если у меня есть перечисления, такие как:

enum EnumA
{
  stuffA = 0
};
enum enumAA
{
  stuffA = 1
};

Что происходит здесь, когда вы ссылаетесь на stuffA? Я думал, что вы будете ссылаться на них как EnumA.stuffA и EnumB.stuffA как в Java, но в C.

это не так

Ответы [ 6 ]

9 голосов
/ 09 декабря 2011

enums не вводите новую область видимости.

В вашем примере второй enum не будет компилироваться из-за конфликта имен stuffA.

Чтобы избежать имениСтолкновение, это обычная практика, чтобы дать элементам enum общий префикс.Для разных перечислений будут использоваться разные префиксы:

enum EnumA
{
  EA_stuffA = 0
};
enum EnumAA
{
  EAA_stuffA = 1
};
7 голосов
/ 09 декабря 2011

Константы перечисления находятся в глобальном пространстве имен (точнее, в пространстве имен обычных идентификаторов , в отличие от меток, тегов и пространств имен членов структуры / объединения), поэтому вы получаете ошибку компиляции на второй stuffA.

Нельзя использовать два разных значения для одного и того же имени перечисления (или одного и того же значения, указанного дважды) в одной единице перевода.

6 голосов
/ 09 декабря 2011

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

enum EnumA
{
  stuffA = 0
};

void func(void) {
   enum enumAA
   {
     stuffA = 1
   };
   // do something
}

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

1 голос
/ 09 декабря 2011

Как уже упоминалось, это не скомпилируется, так как stuffA определяется дважды. Enum-значения просто ссылаются на перечисление (то есть "stuffA", а не EnumA.stuffA). Вы даже можете использовать их для типов, которые не являются перечислениями (например, целые числа). Перечисления иногда используются таким образом с целыми числами, подобно тому, как можно было бы определить #define константы.

0 голосов
/ 08 апреля 2019

Этот ответ показывает, как правила 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 . Дальнейшие параграфы в этом пункте объясняют понятие области действия и четырех видов области действия: функция, файл, блок и прототип функции. Они не влияют на приведенный выше анализ, поскольку приведенный выше код находится в одной области видимости.)

0 голосов
/ 21 мая 2018

В зависимости от того, где вы объявляете эти перечисления, вы также можете объявлять новые области, используя ключевое слово namespace.

ПРИМЕЧАНИЕ. Я бы не рекомендовал делать это, просто отмечаю, что это возможно.Вместо этого было бы лучше использовать префикс, как отмечено в других примерах.

namespace EnumA
{
    enum EnumA_e
    {
        stuffA = 0
    };
};

namespace EnumAA
{
    enum enumAA_e
    {
        stuffA = 1
    };
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...