Перейти к содержанию
    

Как определить размер структуры в макросе?

Добрый день.

 

Дано:

8 битный микроконтроллер

Keil Си

Структура для хранения переменных во внешней I2C EPROM

Размер EPROM константа 256 байт

Структура постепенно растет и изменяется

 

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

 

Что-то типа того:

typdef struct
{
...
}структура;

#define размер EPROM 256

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

 

Но sizeof в данном случае использовать нельзя.

Подскажите пожалуйста, как мне решить мою задачу? (считать вручную уже надоело)

Изменено пользователем AndreyS

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно вот такой хак применить, воспользовавшись, тем фактом, что массив не может иметь отрицательный размер:

 

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 в частности.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

http://msdn.microsoft.com/en-us/library/ew...28VS.80%29.aspx

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

sizeof в препроцессоре понимали какие-то ранние версии компиляторов IAR.

А для проверки можно тупо написать if в теле программы. Все равно компилятор при оптимизации его выкинет, если условие не выполняется.

Можно даже вызывать какую-нибуь левую подпрограииу, чтобы обругался линкер:

 

void linker_error(void);


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

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

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно довольно много языковых конструкций использовать для этих целей. Особенно тех, правильность которых зависит от значений целочисленных выражений. switch, например, можно использовать с дублирующимися метками. Да много чего ещё.

А вот в С++ есть такая штука как STATIC_ASSERT, реализацию которого можно найти, например, в boost (А как утвердят новый стандарт -это будет часть языка).

И можно писать в любом месте программы так:

 

BOOST_STATIC_ASSERT(sizeof(A) < 256)

 

Если условие итненно - всё нормально, ложно - ошибка компиляции.

Я лично именно BOOST_STATIC_ASSERT использую в таких случаях (и пишу на С++ соответственно).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я лично именно BOOST_STATIC_ASSERT использую в таких случаях (и пишу на С++ соответственно).

 

STATIC_ASSERT уже является частью Visual Studio 2010

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

STATIC_ASSERT уже является частью Visual Studio 2010

Он является частью нового стандарта С++.

И в GCC он уже тоже есть. Но стандарт ещё не принят.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всем большое спасибо.

 

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

 

Жалко конструкция vmp на Keil не сработала. Он упорно пытался найти все что под if (хотя после компиляции его выкинул)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

можно добавить extern:

#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 ] 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

#define OFFSET(type,field) ((uchar *)&(((type *)0)->field) - (uchar *)0)

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

#define OFFSET(type,field) ((uchar *)&(((type *)0)->field) - (uchar *)0)

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

 

Вот только топикстартера интересовал другой вопрос :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...