В моей повседневной работе я столкнулся с большим количеством кодов C, напоминающих следующий шаблон. Я беспокоюсь, безопасен ли этот шаблон.Безопасно ли использовать индекс вне диапазона с меньшим массивом, который вытесняется из достаточно большого массива?
typedef struct
{
unsigned char someField : 4;
unsigned char someOtherField : 4;
unsigned char body[1];
} __attribute__((__packed__, aligned(1))) SomeStruct;
int main()
{
unsigned char pack[16] = {};
SomeStruct* structPack = (SomeStruct*)pack;
structPack->someField = 0xC;
structPack->body[4] = 0x5;
return 0;
}
Что заставляет меня беспокоиться, что программа использует structPack->body[4]
, который по-прежнему является частью массива 16 байт, но вне переплете, если мы посмотрим на определение SomeStruct
. Таким образом, есть два способа взглянуть на это:
- Это ссылка на действительную ячейку памяти. Нет опасности.
- Это внеочередное, поэтому неопределенное поведение.
Итак, мои вопросы:
- Согласно стандарту C (более конкретно, C89), эта модель безопасна или неопределенное поведение?
- Кроме того, для некоторых конкретных компиляторов (особенно GCC) или платформы это безопасно?
- Есть ли лучшие альтернативы?
Обратите внимание, что этот тип кода в основном работает на микроконтроллерах и иногда работает как приложение на рабочем столе Linux.
Я считаю это небезопасным и в лучшем случае вводит в заблуждение. Нет смысла делать это. Если код, написанный в 'structPack-> body [4]', был перемещен в другое место, и он больше не указывал на больший буфер, у вас проблемы. Или, если кто-то решит создать массив SomeStruct, у вас будет плохое время. –
Если тело представляет собой массив размером 1, то почему вы хотите получить доступ к 5-му элементу? Что-то не так с вашей логикой здесь. –
@NeilKirk Это обычно используемый шаблон в C для выделения одного объекта с массивом переменной длины в конце. Обычно объект выделяется через 'malloc'. Но не знаю, строго ли это законно или нет. – Keith