Значение RTNLGRP_NEIGH
будет 3. Вы можете легко проверить это с помощью следующей программы.
#include <stdio.h>
/* RTnetlink multicast groups */
enum rtnetlink_groups {
RTNLGRP_NONE,
#define RTNLGRP_NONE RTNLGRP_NONE
RTNLGRP_LINK,
#define RTNLGRP_LINK RTNLGRP_LINK
RTNLGRP_NOTIFY,
#define RTNLGRP_NOTIFY RTNLGRP_NOTIFY
RTNLGRP_NEIGH,
#define RTNLGRP_NEIGH RTNLGRP_NEIGH
RTNLGRP_TC,
#define RTNLGRP_TC RTNLGRP_TC
RTNLGRP_IPV4_IFADDR,
#define RTNLGRP_IPV4_IFADDR RTNLGRP_IPV4_IFADDR
/* ... */
#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR
RTNLGRP_PHONET_ROUTE,
#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE
__RTNLGRP_MAX
};
#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
int
main()
{
printf("RTNLGRP_NEIGH = %d\n", RTNLGRP_NEIGH);
}
Он выводит это:
RTNLGRP_NEIGH = 3
Поскольку каждый макрос #define
д к своему собственному имени, RTNLGRP_NEIGH
в main
будет заменен RTNLGRP_NEIGH
. Но так как расширение не является рекурсивным, он остановится в этой точке и программа использовать enum
постоянной RTNLGRP_NEIGH
, который является четвертым и, следовательно, имеет значение 3.
Если вы не уверены, что делает препроцессор, вы всегда можете скомпилировать с переключателем -E
и посмотрите на предварительно обработанный выход. Сборка приведенного выше примера с gcc -E
дает (не показано 840 линий #include
д стандартных заголовков библиотеки)
# 4 "main.c"
enum rtnetlink_groups {
RTNLGRP_NONE,
RTNLGRP_LINK,
RTNLGRP_NOTIFY,
RTNLGRP_NEIGH,
RTNLGRP_TC,
RTNLGRP_IPV4_IFADDR,
RTNLGRP_PHONET_ROUTE,
__RTNLGRP_MAX
};
int
main()
{
printf("RTNLGRP_NEIGH = %d\n", RTNLGRP_NEIGH);
}
, который является ее будет гораздо менее запутанной.
#define
s, смешанный с определением enum
, не влияют на определение enum
. Не имеет значения, где расположены #define
. Они могли (и, вероятно, должны были) быть размещены до или после определения.
/* RTnetlink multicast groups */
enum rtnetlink_groups {
RTNLGRP_NONE,
RTNLGRP_LINK,
RTNLGRP_NOTIFY,
RTNLGRP_NEIGH,
RTNLGRP_TC,
RTNLGRP_IPV4_IFADDR,
/* ... */
RTNLGRP_PHONET_ROUTE,
__RTNLGRP_MAX
};
#define RTNLGRP_NONE RTNLGRP_NONE
#define RTNLGRP_LINK RTNLGRP_LINK
#define RTNLGRP_NOTIFY RTNLGRP_NOTIFY
#define RTNLGRP_NEIGH RTNLGRP_NEIGH
#define RTNLGRP_TC RTNLGRP_TC
#define RTNLGRP_IPV4_IFADDR RTNLGRP_IPV4_IFADDR
#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR
/* ... */
#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE
#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
Причина они писали этот weired код, вероятно, что они хотели, чтобы реорганизовать старый код, используя
#define RTNLGRP_NONE 0
#define RTNLGRP_LINK 1
#define RTNLGRP_NOTIFY 2
#define RTNLGRP_NEIGH 3
#define RTNLGRP_TC 4
#define RTNLGRP_IPV4_IFADDR 5
/* ... */
использовать enum
вместо этого. Но поскольку существующий код может опираться на то, что идентификаторы являются макросами (например, тестирование #ifdef RTNLGRP_NEIGH
), они хотели бы предоставить макросы с одинаковым значением. Обратите внимание, что этот подход является ошибочным, однако, поскольку препроцессор не будет знать значение константы, поэтому вы не можете делать такие вещи, как #if RTNLGRP_NEIGH >= 3
, которые могли бы иметь: RTNLGRP_NEIGH
были #define
d до 3
буквально. Таким образом, по сути, их подход сочетает в себе недостатки использования макросов (загрязнение именных пространств) с использованием enum
с (недоступно во время предварительной обработки).
Возможно, более полезный образец, который я видел ранее, составляет #define
константы для действительных целых чисел.
enum rtnetlink_groups {
RTNLGRP_NONE
#define RTNLGRP_NONE 0
= RTNLGRP_NONE,
RTNLGRP_LINK
#define RTNLGRP_LINK 1
= RTNLGRP_LINK,
RTNLGRP_NOTIFY
#define RTNLGRP_NOTIFY 2
= RTNLGRP_NOTIFY,
RTNLGRP_NEIGH
#define RTNLGRP_NEIGH 3
= RTNLGRP_NEIGH,
RTNLGRP_TC
#define RTNLGRP_TC 4
= RTNLGRP_TC,
RTNLGRP_IPV4_IFADDR
#define RTNLGRP_IPV4_IFADDR 5
= RTNLGRP_IPV4_IFADDR,
/* ... */
};
который будет предварительно обработан следующим образом.
enum rtnetlink_groups {
RTNLGRP_NONE
= 0,
RTNLGRP_LINK
= 1,
RTNLGRP_NOTIFY
= 2,
RTNLGRP_NEIGH
= 3,
RTNLGRP_TC
= 4,
RTNLGRP_IPV4_IFADDR
= 5,
};
Обратите внимание, что здесь, это очень важно, что #define
s смешивает в enum
определения, в противном случае мы получим неверный код, такие как 3 = 3,
вместо желаемого RTNLGRP_NEIGH = 3
.
О, и, пожалуйста, не используйте __RTNLGRP_MAX
как идентификатор. Имена, содержащие два смежных подчеркивания или начинающиеся с символа подчеркивания, за которым следует буква верхнего регистра, зарезервированы по стандарту C. Использование их в вашем собственном коде приводит к неопределенному поведению.
оригинальный автор должен знать лучше, чем смешивать #define и перечислять как это, выглядит как беспорядок –