битовая дополненная структура внутри объединения и приведения типов

#c #struct #unions

#c #структура #объединения

Вопрос:

У меня есть неподписанное 64-разрядное слово и немного дополненная структура, которые оба приведены ниже.Структура находится внутри объединения, которое содержит несколько (11, если быть точным) похожих, но слегка измененных структур.

 uint64_t final_data_word;

#pragma pack(1)
typedef struct control_block_format_1_s
{
    uint8_t block_type_field:8;
    uint8_t control_word_0:7;
    uint8_t control_word_1:7;
    uint8_t control_word_2:7;
    uint8_t control_word_3:7;
    uint8_t control_word_4:7;
    uint8_t control_word_5:7;
    uint8_t control_word_6:7;
    uint8_t control_word_7:7;
}control_block_format_1_t;

typedef union
{
    control_block_format_1_t *cb_1;
    control_block_format_2_t *cb_2;
    control_block_format_3_t *cb_3;
    control_block_format_4_t *cb_4;
    control_block_format_5_t *cb_5;
    control_block_format_6_t *cb_6;
    control_block_format_7_t *cb_7;
    control_block_format_8_t *cb_8;
    control_block_format_9_t *cb_9;
    control_block_format_10_t *cb_10;
    control_block_format_11_t *cb_11;
}block_payload_union_t;
#pragma pack()
  

Я хочу интерпретировать 64 бита в 64-разрядном word как поля в структуре.итак, я выполняю приведенную ниже операцию

 block_payload_union_t *block_pload =(block_payload_union_t*)malloc(sizeof(block_payload_union_t*));
block_pload->cb_1 = (control_block_format_1_t*)(amp;final_data_word);
  

но я не получаю ожидаемые значения для последнего поля в моей структуре.Кто-нибудь видит какие-либо проблемы с тем, что я делаю?Приветствуются любые предложения или комментарии.

@Jonathan Я добавил следующие комментарии к своему коду.
printf(«sizeof(объединение) = %zun», sizeof(block_payload_union_t));

printf(«sizeof(cb1) = %zun», sizeof(control_block_format_1_t));

printf(«FDW = 0x%.16lxn», final_data_word);

//printf(«*bp-> llp = 0x%.16lxn», *block_pload->llp);

printf(«bp->cb1->block_type_fld = 0x%.2Xn», block_pload->cb_1->block_type_field);

printf(«bp->cb1->control_word_0 = 0x%.2Xn», block_pload->cb_1->control_word_0);

printf(«bp-> cb1->control_word_1 = 0x%.2Xn», block_pload->cb_1->control_word_1);

printf(«bp->cb1->control_word_2 = 0x%.2Xn», block_pload->cb_1->control_word_2);

printf(«bp-> cb1->control_word_3 = 0x%.2Xn», block_pload->cb_1->control_word_3);

printf(«bp->cb1->control_word_4 = 0x%.2Xn», block_pload->cb_1->control_word_4);

printf(«bp->cb1->control_word_5 = 0x%.2Xn», block_pload->cb_1->control_word_5);

printf(«bp-> cb1->control_word_6 = 0x%.2Xn», block_pload->cb_1->control_word_6);

printf(«bp->cb1->control_word_7 = 0x%.2Xn», block_pload->cb_1->control_word_7);

Результат, который я получил без #pragma pack (), был следующим

конечное слово данных 0x1e00000000000000

sizeof (объединение) = 8

sizeof(cb1) = 9

FDW = 0x1e00000000000000

bp->cb1->block_type_fld = 0x00

bp-> cb1->control_word_0 = 0x00

bp-> cb1->control_word_1 = 0x00

bp-> cb1->control_word_2 = 0x00

bp-> cb1->control_word_3 = 0x00

bp-> cb1->control_word_4 = 0x00

bp-> cb1->control_word_5 = 0x00

bp-> cb1->control_word_6 = 0x1E

bp-> cb1->control_word_7 = 0x78

Результат с помощью #pragma pack() был следующим

конечное слово данных 0x1e00000000000000

sizeof (объединение) = 8

sizeof(cb1) = 8

FDW = 0x1e00000000000000

bp->cb1->block_type_fld = 0x00

bp-> cb1->control_word_0 = 0x00

bp-> cb1->control_word_1 = 0x00

bp-> cb1->control_word_2 = 0x00

bp-> cb1->control_word_3 = 0x00

bp-> cb1->control_word_4 = 0x00

bp-> cb1->control_word_5 = 0x00

bp-> cb1->control_word_6 = 0x00

bp->cb1->control_word_7 = 0x0F

которая похожа на результат, который вы получили на компьютере Джонатана.

Комментарии:

1. Похоже, вас смущает разница между объектом и указателем на объект

Ответ №1:

Вы должны использовать sizeof(block_payload_union_t) вместо sizeof(block_payload_union_t *) при вызове malloc() . Однако на 64-разрядной машине это, вероятно, дает вам тот же размер (8), так что вам это сойдет с рук, несмотря на то, что это неправильно.

Немного странно, что ваш block_payload_union_t содержит указатели на ваши макеты полей вместо того, чтобы содержать фактические значения.

Вы не показали нам объявление final_data_word . Вы проверили размер вашего объединения по сравнению с ожидаемым размером?


На компьютере Mac под управлением Lion (10.7.2) я получаю этот вывод из программы, которая следует:

Вывод

С #pragma pack(1) :

 sizeof(union) = 8
sizeof(cb1) = 8
FDW = 0xFEDCBA9876543210
*bp->llp = 0xFEDCBA9876543210
bp->cb1->block_type_fld = 0x10
bp->cb1->control_word_0 = 0x32
bp->cb1->control_word_1 = 0x28
bp->cb1->control_word_2 = 0x59
bp->cb1->control_word_3 = 0x43
bp->cb1->control_word_4 = 0x29
bp->cb1->control_word_5 = 0x17
bp->cb1->control_word_6 = 0x37
bp->cb1->control_word_7 = 0x7F
  

Без #pragma pack(1) :

 sizeof(union) = 8
sizeof(cb1) = 9
FDW = 0xFEDCBA9876543210
*bp->llp = 0xFEDCBA9876543210
bp->cb1->block_type_fld = 0x10
bp->cb1->control_word_0 = 0x32
bp->cb1->control_word_1 = 0x54
bp->cb1->control_word_2 = 0x76
bp->cb1->control_word_3 = 0x18
bp->cb1->control_word_4 = 0x3A
bp->cb1->control_word_5 = 0x5C
bp->cb1->control_word_6 = 0x7E
bp->cb1->control_word_7 = 0x10
  

Что вы получаете?

Программа

 #include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#pragma pack(1)
typedef struct control_block_format_1_s
{
    uint8_t block_type_field:8;
    uint8_t control_word_0:7;
    uint8_t control_word_1:7;
    uint8_t control_word_2:7;
    uint8_t control_word_3:7;
    uint8_t control_word_4:7;
    uint8_t control_word_5:7;
    uint8_t control_word_6:7;
    uint8_t control_word_7:7;
} control_block_format_1_t;

typedef union
{
    long long *llp;
    control_block_format_1_t *cb_1;
    //control_block_format_2_t *cb_2;
    //control_block_format_3_t *cb_3;
    //control_block_format_4_t *cb_4;
    //control_block_format_5_t *cb_5;
    //control_block_format_6_t *cb_6;
    //control_block_format_7_t *cb_7;
    //control_block_format_8_t *cb_8;
    //control_block_format_9_t *cb_9;
    //control_block_format_10_t *cb_10;
    //control_block_format_11_t *cb_11;
} block_payload_union_t;
#pragma pack()

int main(void)
{
    long long final_data_word = 0xFEDCBA9876543210;
    block_payload_union_t *block_pload =(block_payload_union_t*)malloc(sizeof(block_payload_union_t));
    block_pload->cb_1 = (control_block_format_1_t*)(amp;final_data_word);
    printf("sizeof(union) = %zun", sizeof(block_payload_union_t));
    printf("sizeof(cb1) = %zun", sizeof(control_block_format_1_t));
    printf("FDW = 0x%.16llXn", final_data_word);
    printf("*bp->llp = 0x%.16llXn", *block_pload->llp);
    printf("bp->cb1->block_type_fld = 0x%.2Xn", block_pload->cb_1->block_type_field);
    printf("bp->cb1->control_word_0 = 0x%.2Xn", block_pload->cb_1->control_word_0);
    printf("bp->cb1->control_word_1 = 0x%.2Xn", block_pload->cb_1->control_word_1);
    printf("bp->cb1->control_word_2 = 0x%.2Xn", block_pload->cb_1->control_word_2);
    printf("bp->cb1->control_word_3 = 0x%.2Xn", block_pload->cb_1->control_word_3);
    printf("bp->cb1->control_word_4 = 0x%.2Xn", block_pload->cb_1->control_word_4);
    printf("bp->cb1->control_word_5 = 0x%.2Xn", block_pload->cb_1->control_word_5);
    printf("bp->cb1->control_word_6 = 0x%.2Xn", block_pload->cb_1->control_word_6);
    printf("bp->cb1->control_word_7 = 0x%.2Xn", block_pload->cb_1->control_word_7);
    return(0);
}
  

Комментарии:

1. Я не совсем понимаю, что означает этот комментарий. Я не вижу код, на который вы смотрите. Вы также могли бы рассмотреть возможность определения платформы, на которой вы работаете, и используемого компилятора. (Я сказал macOS X 10.7.2; я должен был упомянуть XCode 4.2 от Apple (GCC 4.2.1 для LLVM).)

Ответ №2:

Какой смысл иметь указателей в качестве членов вашего профсоюза? Вы могли бы достичь того же результата с помощью приведений.

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

 typedef union
{
    control_block_format_1_t cb_1;
    control_block_format_2_t cb_2;
    control_block_format_3_t cb_3;
    control_block_format_4_t cb_4;
    control_block_format_5_t cb_5;
    control_block_format_6_t cb_6;
    control_block_format_7_t cb_7;
    control_block_format_8_t cb_8;
    control_block_format_9_t cb_9;
    control_block_format_10_t cb_10;
    control_block_format_11_t cb_11;
} block_payload_union_t;
  

Теперь размер вашей block_payload_union_t структуры составляет всего 64 бита, и вы можете работать с этими данными, используя любую из одиннадцати версий.

Ответ №3:

Директива #pragma pack(1) приведет к тому, что этот элемент будет упакован в структуру с 1-байтовой границей, однако директива #pragma pack выравнивает все битовые поля в структуре / объединении по 1-битным границам. Вот почему последнее поле отключено. Проверьте размер control_block_format_1_s, равен ли он 8 или 9.