2016-11-29 20 views
4

Я пытаюсь статически выделить некоторые структуры, каждая из которых содержит два элемента: указатель на массив структур и размер этого массива.sizeof array literal array

Вот рабочая версия кода:

#define ARRAY_SIZE(x) (sizeof((x))/sizeof((x)[0])) 

struct conf_element { 
     char *key; 
     enum conf_elem_type val_type; 
     void *val_p; 
     tok_t *(*fn_p)(const char *js, jsmntok_t *tok); 
}; 

struct conf_schema { 
     struct conf_element *conf_elems; 
     size_t size; 
}; 

struct conf_element conf_schema_antennae_elems[] = { 
     {"key1_nm", LEAF_INT, NULL, NULL}, 
     {"key2_nm", LEAF_INT, NULL, NULL} 
}; 

struct conf_schema conf_schema_antennae = { 
     conf_schema_antennae_elems, 
     ARRAY_SIZE(conf_schema_antennae_elems) 
}; 

Но вместо того, чтобы определять массив отдельно, а затем ссылки на этот массив при определении структуры, я хотел бы, чтобы инициализировать указатель с массивом буквального в порядке чтобы содержать все это в определении структуры ради того, что я считаю, необходимо увеличить читаемость:

struct conf_schema conf_schema_antennae = { 
     (struct conf_element []) { 
       {"key1_nm", LEAF_INT, NULL, NULL}, 
       {"key2_nm", LEAF_INT, NULL, NULL} 
     }, 
     /* the size of that^compound literal goes here */ 
}; 

можно ли автоматически получить размер этого массива буквального во время компиляции? (Или я злоупотребляя язык и делать вещи сложнее, чем они должны быть?)

EDIT: На основании ответа Олафа на подобный вопрос и комментарий Джона Боллинджера, вот что я закончил с:

#define S(arr) {arr, ARRAY_SIZE(arr)} 

struct conf_schema conf_schema_antennae = S((
     (struct conf_element []) { 
       {"key1_nm", LEAF_INT, NULL, NULL}, 
       {"key2_nm", LEAF_INT, NULL, NULL} 
     } 
)); 

#undef S 
+4

Возможной Дубликат (http://stackoverflow.com/questions/35753494/can-i- reduce-a-long-array-initial-to-a-short-initializer-list-in-c) – Olaf

+2

Если вы разделите свою проблему на [mcve] по мере необходимости, вы попадете в дубликат. Я все еще думаю, что мой ответ - самое ясное и простое решение. Просто примите к вашей проблеме. Если поля не должны быть изменены, вы должны использовать квалификатор 'const' (правильно!). – Olaf

+1

Единственный потенциальный трюк здесь заключается в том, что вам нужно заключить литерал массива в (дополнительные) круглые скобки, когда он используется в качестве аргумента для макроса, например, Олаф описывает в своем ответе, на который он ссылается. Скобки будут препятствовать тому, чтобы запятые в самом литерале принимались как разделители макросов. –

ответ

1

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

Также struct conf_element *conf_elems является указателем, а макрос ARRAY_SIZE не может измерять длину реального массива.

Вы можете увидеть имя скрытой переменной, если скомпилировано с -g. Он отобразит в отладочной информации исполняемого файла переменную с именем __compond_literal.###.

Я предлагаю вам обходное решение: вам действительно нужно знать его размер в клиентском коде? Если нет, то попробуйте следующее: [? Я могу уменьшить длинную инициализацию массива в короткий список инициализаторов в C]

struct conf_schema conf_schema_antennae = { 
     (struct conf_element []) { 
       {"key1_nm", LEAF_INT, NULL, NULL}, 
       {"key2_nm", LEAF_INT, NULL, NULL}, 
       {0, 0, 0, 0} /* Place holder for the end of the array */ 
     } 
}; 

void client_code() 
{ 
    struct conf_element *p_elems = conf_schema_antennae.conf_elems; 

    while (p_elems->key) 
    { 
    /* ... */ 
    p_elems++; 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^