2017-01-23 3 views
2
struct something { 
    uint32_t a; 
    uint8_t b; 
    uint16_t c; 
    uint32_t x; 
    uint16_t y; 
    uint8_t z; 
}; 

uint8_t *data = malloc(14); 
struct something *s = (struct something *)data; 

s->a = 1; 
s->b = 2; 
s->c = 3; 
s->x = 4; 
s->y = 5; 
s->z = 6; 

Всегда ли это безопасно делать это в С или наложение структуры может вызвать проблемы?C проблемы с прокладкой конструкции

Редактировать 1 (уточнить): гарантировано, что данные [0] .. данные [3] == 1, данные [4] == 2, данные [5] .. данные [6] == 3, данные [7] .. данные [10] == 4, данные [11] .. данные [12] == 5 и данные [13] == 6?

Edit 2: маленькая ошибка при редактировании 1

+1

Вы проверили 'sizeof' эту' struct'ure? –

+1

Нет, это не безопасно. Заполнение * будет * проблемой. –

+1

Комментарий после вашего редактирования: Нет, это не из-за возможного заполнения. –

ответ

10

Это не безопасной эксплуатации. Компилятор добавит дополнение в определенную реализацию.

Вообще говоря, член заданного размера будет выровнен по смещению, кратное этому размеру.

Учитывая типичный способ заполнения, этот struct, скорее всего, будет размером 16 байт. Физический макет, скорее всего, (но не обязательно) выглядит следующим образом:

struct something { 
    uint32_t a;   // offset 0 
    uint8_t b;   // offset 4 
         // 1 byte padding 
    uint16_t c;   // offset 6 
    uint32_t x;   // offset 8 
    uint16_t y;   // offset 12 
    uint8_t z;   // offset 14 
    // 1 byte padding 
}; 

Не используйте магические числа. Intead, используйте оператор sizeof.

struct something *s = malloc(sizeof(struct something)); 

EDIT:

Если вы хотите увеличить вероятность того, что ваш struct выложен определенным образом, увидеть это guide to structure packing. Если вы будете следовать этим практикам, есть хороший шанс (но не 100%), что ваш struct будет выложен в памяти так, как вы ожидаете.

Для gcc вы можете использовать __attribute__((packed)) на struct для удаления прокладки с struct. Тем не менее, это может привести к штрафу за производительность или может вызвать ошибку страницы. Параметры -Wpadded и -Wpacked также могут рассказать вам больше о заполнении.

+1

Но если этот порядок и исключение заполнения - это ** требование **, ваш компилятор _may_ имеет инструменты, которые помогут вам (но вы платите за переносимость и, вероятно, за штраф за производительность). –

+0

Будут ли эти смещения отражать данные, хранящиеся в переменной 'data'? Я редактирую вопрос, чтобы было ясно. Я имею в виду, достаточно ли компилятор, чтобы обойти проблемы, вызванные заполнением? –

+0

@ RafaelAlmeida, никакие проблемы не вызваны заполнением, если вы не делаете то, что явно зависит от местоположения или количества отступов. Необычно это нужно делать. Никакая программа, которая делает это, строго соответствует стандарту.В зависимости от предположения о смещении хранилища член структуры, отличный от первого относительно начала структуры, например, о котором вы спрашиваете в своем редактировании, является точно такой несоответствующей вещью. –

2

Hardcoding 14 is крайне непослушный.

Почему бы вам не использовать sizeof(struct something)? Это постоянное выражение для оценки времени компиляции, поэтому накладные расходы на время выполнения отсутствуют.

Ваша догадка правильная: компилятор оставляет за собой право вставлять отступы между элементами структуры, а также в конце конечного элемента. (Обратите внимание, что адрес первого элемента должен быть таким же, как адрес struct.)

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