Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как определить размер структуры в макросе?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
AndreyS
Добрый день.

Дано:
8 битный микроконтроллер
Keil Си
Структура для хранения переменных во внешней I2C EPROM
Размер EPROM константа 256 байт
Структура постепенно растет и изменяется

Хотел включить макрос проверки размера структура за предел размер памяти EPROM на стадии компиляции и в случае превышеняи размера выводить ошибку.

Что-то типа того:
Код
typdef struct
{
...
}структура;

#define размер EPROM 256

#if (sizeof(структура)>размер EPROM)
#error "ОШИБКА"
#endif


Но sizeof в данном случае использовать нельзя.
Подскажите пожалуйста, как мне решить мою задачу? (считать вручную уже надоело)
neiver
Можно вот такой хак применить, воспользовавшись, тем фактом, что массив не может иметь отрицательный размер:

Код
struct A
{
    int a, b, c, d;
    char e[300];
};

enum{EPROM_SIZE = 256};

static int error_struct_a_is_too_big[sizeof(A) > EPROM_SIZE ? -1: 0];


Если sizeof(A) будет больше EPROM_SIZE, то будет ошибка. Если нет - массив нулевого размера, который оптимизатор выкинет.
Собственно, сообщение нужно закодировать в имени этого массива. Пример сообщения об ошибке, которое выдаёт GCC:
../main.cpp:19: error: size of array 'error_struct_a_is_too_big' is negative


А в макросах это никак не сделать, макросы работают на уровне текстовых строк, им побоку любые языковые конструкции и sizeof в частности.
sergeeff
Макросы обрабатываются препроцессором, то есть до компиляции. sizeof определяется на этапе компиляции. Посему ответ: в лоб на С - никак.

http://msdn.microsoft.com/en-us/library/ew...28VS.80%29.aspx
vmp
sizeof в препроцессоре понимали какие-то ранние версии компиляторов IAR.
А для проверки можно тупо написать if в теле программы. Все равно компилятор при оптимизации его выкинет, если условие не выполняется.
Можно даже вызывать какую-нибуь левую подпрограииу, чтобы обругался линкер:

Код
void linker_error(void);


void main(void)
{
  if (sizeof(структура)>размер EPROM)
   {
     linker_error();
     for (;;);
   }
}

В этом случае сначала компилятор даст warning на недостижимый код из-за for (;;);, а потом линкер не найдет подпрограмму linker_error.


neiver
Можно довольно много языковых конструкций использовать для этих целей. Особенно тех, правильность которых зависит от значений целочисленных выражений. switch, например, можно использовать с дублирующимися метками. Да много чего ещё.
А вот в С++ есть такая штука как STATIC_ASSERT, реализацию которого можно найти, например, в boost (А как утвердят новый стандарт -это будет часть языка).
И можно писать в любом месте программы так:

Код
BOOST_STATIC_ASSERT(sizeof(A) < 256)


Если условие итненно - всё нормально, ложно - ошибка компиляции.
Я лично именно BOOST_STATIC_ASSERT использую в таких случаях (и пишу на С++ соответственно).
sergeeff
Цитата(neiver @ Sep 27 2010, 19:02) *
Я лично именно BOOST_STATIC_ASSERT использую в таких случаях (и пишу на С++ соответственно).


STATIC_ASSERT уже является частью Visual Studio 2010
neiver
Цитата(sergeeff @ Sep 27 2010, 20:36) *
STATIC_ASSERT уже является частью Visual Studio 2010

Он является частью нового стандарта С++.
И в GCC он уже тоже есть. Но стандарт ещё не принят.
AndreyS
Всем большое спасибо.

Сделал костыль предложенный neiver (хоть и пришлось пожертвовать одним байтом ОЗУ. 0 длины массив не создал. Вернее не выкинул его, а ругнулся при требуемом типе оптимизации.)

Жалко конструкция vmp на Keil не сработала. Он упорно пытался найти все что под if (хотя после компиляции его выкинул)
Diz
Если волнует, что компилятор выделит память переменной (при ненулевом уровне оптимизации должен выбросить),
можно добавить extern:
CODE
#define CAT(a, b) a##b
#define CAT_WRAP(prefix, line) CAT(prefix, line)
#define PANIC_IF(arg) extern char CAT_WRAP(AssertAtLine, __LINE__) [ (arg) ? -1 : 1 ]


Dog Pawlowa
Есть такой макрос определения смещения поля в структуре, в ИАРе он встроенный, его использовать.

#define OFFSET(type,field) ((uchar *)&(((type *)0)->field) - (uchar *)0)
_Pasha
Цитата(Dog Pawlowa @ Oct 1 2010, 09:25) *
#define OFFSET...

Вообще-то он должен offsetof называться....
Dog Pawlowa
Цитата(_Pasha @ Oct 1 2010, 12:34) *
offsetof

Может быть, я то свой определил.
esaulenka
Цитата(Dog Pawlowa @ Oct 1 2010, 10:25) *
Есть такой макрос определения смещения поля в структуре, в ИАРе он встроенный, его использовать.
#define OFFSET(type,field) ((uchar *)&(((type *)0)->field) - (uchar *)0)

Плюс адин к мнению _Pasha, лучше делать #include <stddef.h> и использовать стандартный offsetof().

Вот только топикстартера интересовал другой вопрос smile.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.