Один общий подход, о котором я не упоминал здесь, заключается в том, чтобы запустить HTML через Tidy , который может быть настроен на выдачу гарантированного действительного XHTML. Затем вы можете использовать любую старую библиотеку XML.
Но к вашей конкретной проблеме вы должны взглянуть на этот проект: http://fivefilters.org/content-only/ - это модифицированная версия алгоритма Readability , который предназначен для извлечения только текстового содержимого (а не верхних и нижних колонтитулов) со страницы.
Значение 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
d для своего имени, RTNLGRP_NEIGH
в main
будет заменен на RTNLGRP_NEIGH
. Но так как расширение не является рекурсивным, оно останавливается в этой точке, и программа использует константу enum
, которая является четвертой и поэтому имеет значение 3.
Если вы не знаете, что препроцессор, вы всегда можете скомпилировать с помощью переключателя -E
и посмотреть на предварительно обработанный вывод. Компиляция приведенного выше примера с gcc -E
дает (не отображая 840 строк стандартных заголовков библиотеки #include
d)
# 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
s. Они могли (и, вероятно, должны были) быть размещены до или после определения.
/* 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)
Причина, по которой они написали этот прошитый код, вероятно, что они хотели реорганизовать старый код с помощью
#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
s (недоступно во время предварительной обработки).
Возможно, более полезный образец I прежде были #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. Использование их в вашем собственном коде приводит к неопределенному поведению.
Значение RTNLGRP_NEIGH
будет равно 3 (это четвертая константа перечисления: RTNLGRP_NONE
имеет значение 0, RTNLGRP_LINK
имеет значение 1, а RTNLGRP_NOTIFY
имеет значение 2).
Материал #define
несколько странный - это то, что может заставить людей хотеть остановить вас, используя предварительный процессор C .
Идея заключается в том, что он дает вам макрос для RTNLGRP_NEIGH
, который можно протестировать, но расширение макроса является константой перечисления (записано то же самое). В расширениях нет бесконечного цикла, поскольку после того, как макрос был расширен, он снова не расширяется при повторном сканировании текста замены.
Итак, результат заключается в том, что вы можете написать:
#ifdef RTNLGRP_NEIGH
…code using RTNLGRP_NEIGH…
#endif