Перейти к содержанию
    

Переопределение элементов enum через #define - зачем?

Добрый день. Наткнулся вот на такую конструкцию в заголовочном файле (linux):

/* Bits to be set in the FLAGS parameter of `timerfd_create'.  */
enum
  {
    TFD_CLOEXEC = 02000000,
#define TFD_CLOEXEC TFD_CLOEXEC
    TFD_NONBLOCK = 00004000
#define TFD_NONBLOCK TFD_NONBLOCK
  };

Кто-нибудь может предположить, зачем надо было переопределять элементы перечисления через идентичные define-ы?

Изменено пользователем Harvester

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Harvester сказал:

Кто-нибудь может предположить, зачем надо было переопределять элементы перечисления через идентичные define-ы?

Почему решили что тут что-то "переопределяется"?

Имхо: это просто способ зациклить препроцессор в случае если от строки #define TFD_CLOEXEC TFD_CLOEXEC и до строки #undef TFD_CLOEXEC встретится любое выражение, в котором есть TFD_CLOEXEC.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

27 minutes ago, jcxz said:

Почему решили что тут что-то "переопределяется"?

Имхо: это просто способ зациклить препроцессор в случае если от строки #define TFD_CLOEXEC TFD_CLOEXEC и до строки #undef TFD_CLOEXEC встретится любое выражение, в котором есть TFD_CLOEXEC.

Может я неправильно выразился. Но ведь здесь явно определяется элемент перечисления , а потом с этим же идентификатором написан define.

Исходя из логики работы препроцессора все включения TFD_CLOEXEC будут заменены на идентичную строку, что в свою очередь будет обращением к элементу перечисления. Какое-то тройное "масло-масляное" получается :)

Потому и вопрос возник - зачем?

А Ваше предположение мне кажется неверным. Эти константы используются как битовые параметры, а не как директивы условной компиляции.

timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);

И такое объединение enum + define встречается не в одном файле.

 

Кстати, интересный вопрос - можно ли будет обратиться к элементу перечисления TFD_CLOEXEC, после того, как в коде появится #undef TFD_CLOEXEC?

4 minutes ago, _4afc_ said:

enum для красоты, define чтобы флаги по или складывать

А в чем здесь красота? Дополнительные 5 строк кода, не несущие ни логической, ни пояснительной нагрузки.

Изменено пользователем Harvester

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 минут назад, _4afc_ сказал:

enum для красоты, define чтобы флаги по или складывать

+ чтобы можно было проверить наличие этого enum с помощью #ifdef

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 минут назад, Harvester сказал:

Исходя из логики работы препроцессора все включения TFD_CLOEXEC будут заменены на идентичную строку, что в свою очередь будет обращением к элементу перечисления.

Видимо Вы плохо представляете работу препроцессора.

шаг1. Препроцессор ищет в строке известные ему макросы и, если находит в строке известный ему макрос, выполняет текстовую замену имени макроса на его значение, и переходит к шагу2. Если не находит - переходит к шагу3.

шаг2. После замены он переходит к шагу1.

шаг3. Отдаёт строку компилятору.

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

 

PS: Всё это имхо, исходя из логики работы препроцессора, не проверял. 

10 минут назад, Harvester сказал:

Кстати, интересный вопрос - можно ли будет обратиться к элементу перечисления TFD_CLOEXEC, после того, как в коде появится #undef TFD_CLOEXEC?

Очевидно, что после #undef в библиотеке имён препроцессора не должно быть более этого имени. Соответственно - он никак не будет реагировать на эту лексему в обрабатываемых строках.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

43 minutes ago, Harvester said:

А в чем здесь красота? Дополнительные 5 строк кода, не несущие ни логической, ни пояснительной нагрузки.

Говорят дебагеры при использовании enum напишут TFD_CLOEXEC вместо числа.

 

41 minutes ago, _3m said:

+ чтобы можно было проверить наличие этого enum с помощью #ifdef

Можно попробовать проверить #if

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Полагаю, что enum для автоматического нумерования констант без пропусков, а #define для возможности делать проверки препроцессором (#ifdef). 

5 минут назад, _4afc_ сказал:

Можно попробовать проверить #if

Не получится. На этапе работы препроцессора зачений еще нет, а #if для имени без значения эквивалентен #if 0

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может это потом как-то используется с применением # или ## в макросах?

Беглое гугление дает здравое предположение, совпадающее с версией Сергея и 3м.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

возможно ещё в качестве защиты, что бы дальше кто нибудь не написал #define TFD_CLOEXEC  чегонибудь

На такое компилатор выдаст варнинг (на переопределение дефайна)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проверил: IAR по-крайней мере имеет видимо какую-то защиту от бесконечной рекурсии при макроподстановке - не зацикливается.

Кроме вышеназванных вариантов, такой способ можно ещё использовать для подстановки неких значений вместо элементов списка на этапе компиляции.

Например если есть список кодов ошибок и в каких-то местах нужно иметь их коды, а в каких-то строковую расшифровку:

#define concatAB_(a, b) a##b
#define concatAB(a, b) concatAB_(a, b)

#define STR_TFD_CLOEXEC "error 1"
#define STR_TFD_NONBLOCK "error 2"
enum {
    TFD_CLOEXEC = 02000000,
    #define TFD_CLOEXEC TFD_CLOEXEC
    TFD_NONBLOCK = 00004000
    #define TFD_NONBLOCK TFD_NONBLOCK
  };
...
  printf("%08X: %s\n", TFD_CLOEXEC, concatAB(STR_, TFD_CLOEXEC)); 
  printf("%08X: %s\n", TFD_NONBLOCK, concatAB(STR_, TFD_NONBLOCK));

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для общего понимания можете почитать это:

https://stackoverflow.com/questions/1674032/static-const-vs-define-vs-enum

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

Для склейки, как jcxz показал, для условной компиляции и т.д. и т.п.
 

to: Сергей Борщ

#ifdef X

...

#endif

#if defined(X) && !defined(Y)

...

#endif

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, demiurg_spb сказал:

to: Сергей Борщ

Это к чему? Если к моему ответу на "Можно попробовать проверить #if", то я это понял как "#if X == чему-то" (или его частный случай "#if X"), что совсем не то же самое, что и #if defined(X)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Про защрту от рекурсии при подстановке которая почему-то оказалась в вашем компиляторе ответ лучше искать в стандарте языка где говорится об правилах работы препроцессора.

Изменено пользователем GenaSPB

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 11/14/2019 at 3:16 PM, Сергей Борщ said:

Это к чему?

#include <stdio.h>
#include <stdlib.h>

enum
{
	TFD_CLOEXEC = 02000000
#define TFD_CLOEXEC TFD_CLOEXEC
};


int main(void)
{
	unsigned int i=0;

	#if defined(TFD_CLOEXEC)
		i |= TFD_CLOEXEC;
	#endif

	printf("i= 0x%08x\n", i); 

	return 0;    
}

Я к тому, что это можно использовать таким образом. И более ни к чему)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...