2014-01-26 2 views
2

Есть ли способ создать макрос, который дает максимальный размер списка типов данных?GCC Preproccesor macro для определения максимального размера нескольких структур

Гол

typedef struct { 
    uint8_t x; 
} A; 

typedef struct { 
    uint16_t x; 
} B; 

typedef struct { 
    uint8_t x[10]; 
} C; 

#define sizeof_max(A,B,C) //compiles to '10' 

Использование

Различных ценностных отображения для общих данных сегмента.

typedef union { 
    uint8_t array[sizeof_max(A,B,C)]; 
    A iso_hugenum_a; 
    B ext_a0; 
    C ext_a1; //and someday down the road 'D' may also get added 
} DATA_SEG; 

Это для встроенного приложения, где устройство реализует базовый протокол ISO_HUGENUM_A. Устройство также должно поддерживать расширения для этого протокола EXT_A0, EXT_A1, EXT_B0. Черт возьми, в этом случае есть реальный шанс, что EXT_C0 покажется по дороге (yuck)!

Примечания

Основной задачей здесь является для системы верхнего уровня, чтобы знать размер дата-сегмента в расширяемой и безопасным способом. Заманчиво просто сказать 'cast as array', когда вам нужно как массив. Но

  • На системном уровне (который не дает эфф о протоколе) есть для чтения, записи и проверки (например, КРР) в этом сегменте данных

  • 2yrs вниз по дороге " EXT_C0 'может прийти. Я хочу, чтобы оставить бедную душу, который наследует мой код с чем-то, что не сломается, когда EXT_C0 растет сегмент данных

Я надеюсь, есть решение, но не нашел его еще нет. Есть идеи? Все размеры будут генерироваться препроцессором, поэтому он кажется идеальным кандидатом для макроса.

-Джастин

+1

Почему вы не можете использовать 'sizeof' some' union'-like your 'DATA_SEG' * без *' array'? –

+2

Разве это не обычный случай использования «союза»? –

+0

удален тег C++; спасибо. –

ответ

3

Следующая Макроопределение делает точно, что вы спросили:

#define sizeof_max(s1,s2,s3) sizeof(union{s1 a; s2 b; s3 c; }) 

Для примера структуры следующие:

size_t s = sizeof_max(A,B,C) ; 

приводит s = 10.

Конечно вы можете опустить элемент массива и просто отбрасывать адрес в DATA_SEG объекта к uint8_t*, когда вы хотите получить доступ в виде массива байт:

DATA_SEG x ; 
uint8_t* array = (uint8_t*)&x ; 

Это позволит DATA_SEG добавить дополнительные структуры, если это необходимо, без необходимости изменения макрос - намного безопаснее и удобнее обслуживать.


Добавлено:

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

typedef union 
{ 
    A iso_hugenum_a; 
    B ext_a0; 
    C ext_a1; 
    D added_someday ; 
} DATA_SEG_U; 

typedef union 
{ 
    uint8_t array[sizeof(DATA_SEG_U)]; 
    DATA_SEG_U data_seg ; 
} DATA_SEG ; 
+0

"* // и когда-нибудь по дороге« D »также может быть добавлено *»: ОП запросил обобщения, и не только для трех членов. – pablo1977

+0

@ pablo1977: Мне нужно подумать об этом. – Clifford

+0

Я просто думал об этом; Дай вам клиффорд! ОЧЕНЬ элегантное решение. Спасибо. –

0

Объединение VARIADIC макросов с многоуровневой предварительной обработки может работать -

Это достигает желаемой цели - до 5 входов.

#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N 

#define VA_NUM_ARGS(...)     VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1) 
#define macro_dispatcher__(func,nargs) funC## nargs 
#define macro_dispatcher_(func, nargs) macro_dispatcher__(func, nargs) 
#define macro_dispatcher(func, ...)  macro_dispatcher_(func, VA_NUM_ARGS(__VA_ARGS__)) 

#define sizeof_max(...) macro_dispatcher(sizeof_max, __VA_ARGS__)(__VA_ARGS__) 

#define sizeof_max1(a)   (sizeof(a)) 
#define sizeof_max2(a,b)  (sizeof(a)>sizeof(b)?sizeof(a):sizeof(b)) 
#define sizeof_max3(a,b,c)  sizeof_max2(sizeof_max2(a,b), c) 
#define sizeof_max4(a,b,c,d) sizeof_max2(sizeof_max3(a,b,c),d) 
#define sizeof_max5(a,b,c,d,e) sizeof_max2(sizeof_max4(a,b,c,d),e) 

Это будет работать для GCC/C99. Это «решение» проблемы, и я публикую здесь, потому что я многому научился и хочу поделиться ею. При этом, прочитайте отказ от ответственности в конце :).

Ссылки

Использование macro_dispatcher() была предоставлена ​​'КФМ' из efesx форума здесь:

Добавление кп # к имени функции также описанный здесь:

Конечно, вот некоторые GCC VARIADIC макро страницы:

Пример

typedef union { 
    uint8_t array[sizeof_max(A,B,C)]; //array is of size 10. 
    A iso_hugenum_a; 
    B ext_a0; 
    C ext_a1; 
} DATA_SEG; 

Разбивка

вы можете попробовать этот код в 'main.c' и компилировать с 'GCC -E main.c' соблюдать макро-Несс:

int main (void) { 
    uint8_t rslt; 

    //preprocs to 'rslt=C;' 
    rslt = VA_NUM_ARGS_IMPL(A,B,C,A,B,C,A); 

    //preprocs to 'rslt=3' 
    rslt = VA_NUM_ARGS(A,B,C); 

    //preprocs to 'rslt=maxN' 
    rslt = macro_dispatcher__(max, N); 

    //preprocs to 'rslt=macro_dispatcher_(max, N);' 
    rslt = macro_dispacther_(max, N); 

    //preprocs to 'rslt=max3;' 
    rslt = macro_dispatcher(max, X, Y, Z); 

    //preprocs to 'sizeof_max1(A)/max2(A,B)/max3(A,B,C)' 
    rslt = sizeof_max(A); 
    rslt = sizeof_max(A,B); 
    rslt = sizeof_max(A,B,C); 


    //Breakdown: 
    //sizeof_max(A,B,C); 
    //macro_dispatcher(sizeof_max, __VA_ARGS__)(__VA_ARGS__) 
    //macro_dispatcher_(sizeof_max, 3)(__VA_ARGS__) 
    //macro_dispatcher__(sizeof_max,3)(__VA_ARGS__) 
    // 
    //Result: 
    //sizeof_max3(__VA_ARGS__) 
    //sizeof_max3(A,B,C) 
    rslt = sizeof_max(A,B,C); 

    return 0; 
} 

(Отказ) Simpler & Безопаснее всегда выигрывает. Поэтому я, скорее всего, поеду с чем-то, самым близким к ответу Клиффорда. Мне не нужно играть в милые трюки, которые будут «банить» кого-то еще по дороге.

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