Jump to content

    

Переопределение элементов 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-ы?

Edited by Harvester

Share this post


Link to post
Share on other sites
1 час назад, Harvester сказал:

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

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

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
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 строк кода, не несущие ни логической, ни пояснительной нагрузки.

Edited by Harvester

Share this post


Link to post
Share on other sites
5 минут назад, _4afc_ сказал:

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

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

Share this post


Link to post
Share on other sites
7 минут назад, Harvester сказал:

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

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

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

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

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

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

 

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

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

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

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

Share this post


Link to post
Share on other sites
43 minutes ago, Harvester said:

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

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

 

41 minutes ago, _3m said:

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

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

Share this post


Link to post
Share on other sites

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

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

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

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

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

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

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

 

Share this post


Link to post
Share on other sites

Проверил: 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));

 

Share this post


Link to post
Share on other sites

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

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

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

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

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

#ifdef X

...

#endif

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

...

#endif

 

Share this post


Link to post
Share on other sites
4 часа назад, demiurg_spb сказал:

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

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

 

Share this post


Link to post
Share on other sites

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

Edited by GenaSPB

Share this post


Link to post
Share on other sites
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;    
}

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now