Назначение указателя заголовка массива на существующий массив в объединении в C - PullRequest
0 голосов
/ 07 сентября 2018

Я бы хотел "приравнять" два массива, где один находится внутри фиксированного объединения (не должно быть изменено). Вместо того, чтобы использовать memcpy, я бы просто указал головку myUnion.RawBytes на головку array. Но компилятор выдает ошибку для myUnion.RawBytes = &array[0]; assignmet. Почему это так? Можно ли как-нибудь обойти эту проблему?

Дефектный код ниже пытается проиллюстрировать это.

#include <stdio.h>

typedef union{
    unsigned char  RawBytes[2];
    unsigned short RawWord;
} MyUnion;

int main(){
    MyUnion myUnion;

    char array[2] = {1, 1};
    myUnion.RawBytes = &array[0];

    printf("%d", myUnion.RawWord);

    return 0;
}

Ошибка:

main.c: In function ‘main’:
main.c:12:22: error: assignment to expression with array type
     myUnion.RawBytes = &array[0];

Ответы [ 3 ]

0 голосов
/ 07 сентября 2018

Правильный способ профсоюзного наказания.

#include <stdio.h>

typedef union{
    unsigned char  RawBytes[2];
    unsigned short RawWord;
} MyUnion;

int main(){
    MyUnion myUnion;

    char array[2] = {1, 1};
    myUnion.RawBytes[0] = array[0];
    myUnion.RawBytes[1] = array[1];

    printf("%d", myUnion.RawWord);

    return 0;
}
0 голосов
/ 07 сентября 2018

Я читаю вопрос как Можно ли взять любой массив из 2 символов и интерпретировать его значение как unsigned short без копирования, используя этот умный union трюк , и ответ нет, вы не можете .

Причина не в том, что строгое наложение имен, но в том, что оно может нарушать требования выравнивания. Почти все платформы имеют требование выравнивания не менее 2 для unsigned short. Поведение равно undefined , если указатель преобразуется в другой, не имеющий фундаментального требования выравнивания.

Да, это может аварийно завершить работу на x86 . Забудьте о возможности доступа к невыровненным объектам с помощью машинного языка - вы программируете на C , а не на ассемблере.


правильный способ сделать это - использовать memcpy, который будет сообщать компилятору, что доступ может быть не выровнен, т.е.

char array[2] = {1, 1};
uint16_t raw_word;
memcpy(&raw_word, array, 2);

Обратите внимание, что memcpy является стандартной библиотечной функцией, и компилятору разрешено генерировать машинный код любого типа , если он ведет себя , как если бы была вызвана функция memcpy из стандартной библиотеки.

0 голосов
/ 07 сентября 2018

Для решения своей задачи вы можете использовать следующий подход.

Примечание. Приведенный ниже подход не следует строгому правилу алиасинга.

#include <stdio.h>

typedef union{
    unsigned char  RawBytes[2];
    unsigned short RawWord;
} MyUnion;

int main(){
    MyUnion *myUnion;

    unsigned char array[2] = {1, 1};
    myUnion = &array;

    printf("%d", myUnion->RawWord);
    printf("\n%d %d", myUnion->RawBytes[0], myUnion->RawBytes[1]);

    return 0;
}

Я настоятельно рекомендую вам иметь массив внутри union и использовать memcpy или for loop.

...