#c
#c
Вопрос:
Я пытаюсь инициализировать массив следующим образом :
static tha_field_info_t person_t_fields[] = {
HA_FIELD_INFO(person_t, name, CHAR)
};
Соответствующие структуры данных:
typedef struct _tha_field_info_{
char fname[128];
DATA_TYPE_t dtype;
unsigned int size;
unsigned int offset;
} tha_field_info_t;
typedef struct _person{
char name[30];
unsigned int age;
} person_t;
Используемые макрокоманды
#define HA_FIELD_OFFSET(st, name) ((int)amp;((st *)0)->name)
#define HA_FIELD_SIZE(st, name) sizeof (((st *)0)->name)
#define HA_FIELD_INFO (st, fname, dtype)
{#fname, dtype, HA_FIELD_SIZE(st, fname), HA_FIELD_OFFSET(st, fname)}
Вижу ошибки компиляции с этим макросом.
tha.h:35:28: error: ‘fname’ undeclared (first use in this function)
tha.h:35:35: error: ‘dtype’ undeclared (first use in this function)
tha.h:36:2: error: expected ‘}’ before ‘{’ token
{#fname, dtype, HA_FIELD_SIZE(st, fname), HA_FIELD_OFFSET(st, fname)}
tha.h:36:3: error: stray ‘#’ in program
{#fname, dtype, HA_FIELD_SIZE(st, fname), HA_FIELD_OFFSET(st, fname)}
Однако, если я жестко закодирую это, тогда он будет работать нормально.
{"name", CHAR, sizeof(((person_t *)0)->name), ((int)amp;((person_t *)0)->name)}
В принципе, я хочу сохранить массив с информацией о поле структуры person_t.
Комментарии:
1. @Rhymoid: О, вау, хорошо заметил. Я хотел бы проголосовать за это; пожалуйста, опубликуйте это в качестве ответа. Спасибо.
2. Вы указываете на пробел после закрывающей скобки i определения макроса. Ну, я попытался удалить пробел, но та же ошибка. Кроме того, я написал много макрокоманд и оставляю много места перед символом продолжения «». Пожалуйста, уточните.
3. Хорошо, понял… у вас орлиный взгляд. : o Спасибо.
4. Как я могу пометить комментарий как ответ?
5. Я опубликовал это как ответ.
Ответ №1:
В C существует два типа директив определения:
#define OBJECT_LIKE_MACRO followed by a "replacement list" of preprocessor tokens
#define FUNCTION_LIKE_MACRO(with, arguments) followed by a replacement list
Что отличает эти два типа макросов, так это токен, который следует за идентификатором после #define
: если это lparen, это функциональный макрос, а в противном случае это объектный макрос. Что такое lparen? Проект N1570 указывает в приложении A раздел 3:
(6.10) lparen:
(
символ, перед которым не стоит пробел
Насколько я знаю, это один из немногих случаев в C, где интервал имеет значение (помимо //
комментариев, сращивания строк и директив предварительной обработки). И это отчасти имеет смысл. В конце концов, как бы препроцессор различал любой функциональный макрос и объектный макрос, у которого есть список замены, начинающийся с (
токена? Например, следующий макрос является объектно-подобным, а не функциональным макросом с неправильным синтаксисом:
#define NULL (void*)0
Давайте теперь ответим на ваш вопрос. Проблема в этих двух строках:
#define HA_FIELD_INFO (st, fname, dtype)
{#fname, dtype, HA_FIELD_SIZE(st, fname), HA_FIELD_OFFSET(st, fname)}
Поскольку (
символу после HA_FIELD_INFO
«предшествует пробел», это не функциональный макрос, который вы предполагали. Просто удалите это пространство:
#define HA_FIELD_INFO(st, fname, dtype)
{#fname, dtype, HA_FIELD_SIZE(st, fname), HA_FIELD_OFFSET(st, fname)}
Комментарии:
1. Другие примеры, где имеет значение интервал:
- -i
,i j
,0x2E 1
. Последнее является неожиданным и очень сложным испытанием даже для продвинутых программистов на C.2. @chqrlie Справедливое замечание, но я в основном имел в виду, что значительный интервал является значительным после токенизации. Я согласен, что
0x2E 1
/0x2E 1
раскрывает очень неприятный дефект в спецификации C11.3. Дефект существует со времен первой версии стандарта. Мне это тоже нравится:
check_pattern(date, "??/??/????");