Хорошие варианты использования для объявления тегов перечислимых типов и имен переменных в C? - PullRequest
1 голос
/ 22 января 2020

Если вам нужны некоторые константы в вашем коде, вы можете объявить их с помощью перечислений:

enum {
    DOG,
    CAT,
    FISH,
};

enum {
    CAR,
    BUS,
    TRAIN,
};

, а затем использовать DOG, BUS, et c. по мере необходимости. Но перечисления могут быть объявлены и в более многословном стиле:

enum animals {
    DOG,
    CAT,
    FISH,
} pets;

enum transport {
    CAR,
    BUS,
    TRAIN,
} vehicles;

Учитывая, что константы перечисления имеют глобальную область видимости и не могут ссылаться на pets.DOG так, как это могут делать структуры и объединения, есть ли какое-то хорошее варианты использования для многословного стиля? Для меня теги типов и имена переменных для перечислений выглядят излишне, даже если они выглядят как структуры, но не могут использоваться как структуры. Я надеюсь, что я что-то упустил, и они действительно имеют хорошее применение.

Есть связанная SO Q & A , где главное предположение состоит в том, что при использовании тегов типа и имен переменных следует использовать перечисления. Таким образом, мой вопрос можно перефразировать следующим образом: «В каких задачах мне не удастся использовать только анонимные перечисления?» Потому что для меня весь смысл перечислений - это константы DOG, CAT, CAR, и я не вижу смысла присваивать одну из них переменной enum. Я все еще учусь, поэтому я уверен, что что-то упустил.

Ответы [ 4 ]

3 голосов
/ 22 января 2020

Вы можете дать enum типам имя в случае, если вы хотите объявить переменные этого типа:

enum animals a1 = DOG;
enum animals a2 = CAT;

Или иметь их в качестве аргументов функции:

void foo(enum animals a);

Пока перечисления считаются целочисленными типами, и вы также можете использовать int для хранения одного из этих значений, а использование переменной типа enum помогает документировать ваш код и делает ваши намерения понятными для читателя.

2 голосов
/ 22 января 2020

"Для меня теги типов и имена переменных для перечислений выглядят довольно избыточными ..."

Значение при использовании последовательного набора именованных целочисленных значений в форме перечислимых список (enum) может показаться на первый взгляд тонким, но становится очень очевидным при использовании в C проектах по нескольким причинам:

  • имен , связанных с перечислимый список обеспечивает самодокументируемый код, то есть, в частности, когда набор имен, выбранных для представления набора перечисляемых значений, образует тему, связанную с поставленной задачей. (Ваше животное enum является хорошим примером, поскольку он может использоваться для перечисления, например, большого списка команд или типов позиций в компании.)
  • Назначение значений по умолчанию в перечисляемом списке: последовательный, начиная с 0, и увеличивается на единицу до конца списка, что приводит к появлению списка уникальных значений, очень хорошо подходящих для использования при индексации массива строк с особым значением или при использовании в операторе switch в качестве постоянного целочисленного значения для каждого из операторов case.

А что касается комментария: "... но преимущество использования типа ANML вместо int минимально, ..."

* 1024 Списки * enum также предоставляют документированное ограничение . Например, использование ANML anml; вместо int anml; в качестве члена struct быстро покажет тем, кто будет поддерживать / обновлять исходный код (в ближайшие месяцы или годы), что существует связанный список связанных значений, которые этот член ограничен в использовании, а не любое случайное целочисленное значение. Это важно, когда будет использоваться перечисляемый список, например. в операторе switch, предназначенном только для обработки набора case операторов, которые соответствуют постоянным целочисленным значениям в этом enum.

Эти два вместе являются частью варианта использования, который я нашел особенно полезно, т. е. использовать перечисления в сочетании со строковыми массивами для выбора контента для пользовательского интерфейса или для поиска по подстроке, например: c.

, например:

typedef enum {
       CAT,
       DOG,
       FISH,
       MAX_ANML
    }ANML;//for use in struct

 char *strings[MAX_ANML] = {"cat","dog","fish"};

    typedef struct {
        char content[80];
        ANML anml;
    }SEARCH;

Где, например, эти две конструкции могут быть использованы вместе с оператором switch:

bool searchBuf(SEARCH *animal)
{
    bool res = FALSE;
    switch (animal->anml) {
        case CAT:
            //use the string animal[type] for a search, or user interface content, etc.
            if(strstr(animal->content, strings[CAT]))
                res = TRUE;
            break;
        case DOG:
            if(strstr(animal->content, strings[DOG]))
                res = TRUE;
            break;
        case FISH:
            if(strstr(animal->content, strings[FISH]))
                res = TRUE;
            break;
    };
    return res;
}

int main(void)
{
    char buffer[] = {"this is a string containing cat."};
    SEARCH search;
    strcpy(search.content, buffer);
    search.anml = CAT;

    bool res = searchBuf(&search);
    //use res...

    return 0;    
}
0 голосов
/ 22 января 2020

Я публикую свой собственный ответ после того, как ряд других опубликовал полезные ответы и комментарии, и мы дошли до того, что установили, что перечисленные имена типов и имена переменных полезны в качестве самодокументируемого кода и прояснили смысл кода ( благодаря ответам ryyker и dbu sh).

Поскольку я экспериментировал и искал более веские причины для использования неанонимных перечислений, я установил, что их не может быть по определению. У перечислений нет проверки областей и границ, ни во время компиляции (G CC 6), ни во время выполнения. Вот фрагмент, демонстрирующий слабость:

enum withType { // enum with type name and variable name
    ONE,
    TWO,
    THREE,
} wtEnum;

enum { // Anonymous enum
    TINY,
    SMALL,
    MID,
    LARGE,
    BIGGEST,
};

int main(void) {
    enum withType wt1 = LARGE; // Overflow!
    wtEnum = BIGGEST; // Overflow!
    printf("Enum test values: %d, %d, %d\n", THREE, wt1, wtEnum);
    return 0;
};

В этом примере проясняется, что любая «область видимости», которую вы можете захотеть сделать с именами типов enum и именами переменных, только по соглашению и полагается на дисциплину кодера, чтобы не Перечислите "домены". Я бы go заявил, что с учетом этой реальности функциональность enum в C "неправильно спроектирована". Это создает впечатление той полезности, которую мы видим в структурах и союзах, но ничего подобного не дает. После этого понимания я считаю, что анонимные перечисления являются единственными безопасными перечислениями!

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

0 голосов
/ 22 января 2020

Мне нравятся enums вместо #defines при отладке. Дебюер показывает мне не только значение цифры c, но и имя перечисления - очень удобно

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...