C - преобразование массива без знака в массив без знака

У меня есть целое число без знака (2 байта), и я хочу преобразовать его в тип без знака. Из моего поиска я обнаружил, что большинство людей рекомендуют делать следующее:

 unsigned int x;
 ...
 unsigned char ch = (unsigned char)x;

Правильный ли подход? Я спрашиваю, потому что unsigned char равен 1 байту, и мы преобразуем данные из 2 байтов в 1 байт.

Чтобы предотвратить потерю данных, я хочу создать массив без знака char[] и сохранить отдельные байты в массив. Я застрял в следующем:

 unsigned char ch[2];
 unsigned int num = 272;

 for(i=0; i<2; i++){
      // how should the individual bytes from num be saved in ch[0] and ch[1] ??
 }

Кроме того, как бы мы преобразовали unsigned char[2] обратно в unsigned int.

Большое спасибо.

7 ответов

Решение

Ты можешь использовать memcpy в таком случае:

memcpy(ch, (char*)&num, 2); /* although sizeof(int) would be better */

Кроме того, как преобразовать unsigned char[2] обратно в unsigned int.

Точно так же, просто измените аргументы memcpy.

Как насчет:

ch[0] = num & 0xFF;
ch[1] = (num >> 8) & 0xFF;

Обратная операция оставлена ​​в качестве упражнения.

Как насчет использования союза?

union {
    unsigned int num;
    unsigned char ch[2];
}  theValue;

theValue.num = 272;
printf("The two bytes: %d and %d\n", theValue.ch[0], theValue.ch[1]);

Это действительно зависит от вашей цели: почему вы хотите преобразовать это в unsigned char? В зависимости от ответа на это есть несколько разных способов сделать это:

  • Обрезать: это то, что было рекомендовано. Если вы просто пытаетесь сжать данные в функцию, которая требует unsigned char, просто снимали uchar ch = (uchar)x (но, конечно, остерегайтесь того, что происходит, если ваш int слишком велик).

  • Конкретный порядковый номер: используйте это, когда пункт назначения требует определенного формата. Обычно сетевому коду нравится все, что преобразовано в массивы с прямым порядком байтов:

    int n = sizeof x;
    for(int y=0; n-->0; y++)
        ch[y] = (x>>(n*8))&0xff;
    

    воля делает это.

  • Машина порядковая Используйте это, когда нет требования к порядку байтов, и данные будут появляться только на одном компьютере. Порядок массива будет меняться в зависимости от архитектуры. Люди обычно заботятся об этом с unions:

    union {int x; char ch[sizeof (int)];} u;
    u.x = 0xf00
    //use u.ch 
    

    с memcpy:

    uchar ch[sizeof(int)];
    memcpy(&ch, &x, sizeof x);
    

    или с очень опасным простым приведением (что является неопределенным поведением и происходит сбой во многих системах):

    char *ch = (unsigned char *)&x;
    

Конечно, массив символов, достаточно большой, чтобы содержать большее значение, должен быть точно таким же большим, как и само это значение. Таким образом, вы можете просто притвориться, что это большее значение уже является массивом символов:

unsigned int x = 12345678;//well, it should be just 1234.
unsigned char* pChars;

pChars = (unsigned char*) &x;

pChars[0];//one byte is here
pChars[1];//another byte here

(Как только вы поймете, что происходит, это можно сделать без каких-либо переменных, все просто приведение)

Вам просто нужно извлечь эти байты, используя bitwise & operator, OxFF шестнадцатеричная маска для извлечения одного байта Пожалуйста, посмотрите на различные битовые операции здесь - http://www.catonmat.net/blog/low-level-bit-hacks-you-absolutely-must-know/

Пример программы выглядит следующим образом:

#include <stdio.h>

int main()
{
    unsigned int i = 0x1122;
    unsigned char c[2];

    c[0] = i & 0xFF;
    c[1] = (i>>8) & 0xFF;

    printf("c[0] = %x \n", c[0]);
    printf("c[1] = %x \n", c[1]);
    printf("i    = %x \n", i);

    return 0;
}

Выход:

$ gcc 1.c 
$ ./a.out 
c[0] = 22 
c[1] = 11 
i    = 1122 
$

Поддерживая предложение @abelenky, использование an было бы более надежным способом сделать это.

      union unsigned_number {
    unsigned int  value;        // An int is 4 bytes long
    unsigned char index[4];     // A char is 1 byte long
};

Особенностью этого типа является то, что компилятор будет выделять память только для самого большого члена нашей структуры данных. unsigned_number, что в данном случае будет 4 байта , так как оба члена (значение и индекс) имеют одинаковый размер. Если бы вместо этого вы определили его как a, у нас было бы 8 байтов , выделенных в памяти, поскольку компилятор выполняет выделение для всех членов a. struct.

Кроме того, и здесь ваша проблема решена, члены unionвсе структуры данных используют одну и ту же ячейку памяти , что означает, что все они ссылаются на одни и те же данные — подумайте об этом как о жесткой ссылке в системах GNU/Linux.

Итак, у нас было бы:

      union unsigned_number my_number;

// Assigning decimal value 202050300 to my_number
// which is represented as 0xC0B0AFC in hex format
my_number.value = 0xC0B0AFC;   // Representation:  Binary - Decimal
                               // Byte 3: 00001100 - 12
                               // Byte 2: 00001011 - 11
                               // Byte 1: 00001010 - 10
                               // Byte 0: 11111100 - 252

// Printing out my_number one byte at time
for (int i = 0; i < (sizeof(my_number.value)); i++)
{
    printf("index[%d]: %u, 0x%x\n", \
        i, my_number.index[i], my_number.index[i]);
}

// Printing out my_number as an unsigned integer
printf("my_number.value: %u, 0x%x", my_number.value, my_number.value);

И выход будет:

      index[0]: 252, 0xfc
index[1]: 10, 0xa
index[2]: 11, 0xb
index[3]: 12, 0xc
my_number.value: 202050300, 0xc0b0afc

И что касается вашего последнего вопроса, нам не придется преобразовывать unsigned char обратно в unsigned int , поскольку значения уже есть. Вам просто нужно выбрать, каким способом вы хотите получить к нему доступ

Примечание 1 : я использую целое число из 4 байтов, чтобы облегчить понимание концепции. Для представленной вами проблемы вы должны использовать:

      union unsigned_number {
    unsigned short int value;        // A short int is 2 bytes long
    unsigned char      index[2];     // A char is 1 byte long
};

Примечание 2 : я назначил byte 0к 252чтобы указать на беззнаковую характеристику нашего indexполе. Был ли он объявлен как signed char, мы бы хотели иметь index[0]: -4, 0xfcкак вывод.

Другие вопросы по тегам