Сохранить int в массиве char? - PullRequest
20 голосов
/ 06 октября 2009

Я хочу сохранить 4-байтовое int в массиве char ... так, чтобы первые 4 расположения массива char были 4 байтами целого.

Затем я хочу вытащить int из массива ...

Кроме того, бонусные баллы, если кто-то может дать мне код для выполнения этого в цикле ... IE записывает как 8 дюймов в массив из 32 байтов.

int har = 0x01010101;
char a[4];
int har2;

// write har into char such that:
// a[0] == 0x01, a[1] == 0x01, a[2] == 0x01, a[3] == 0x01 etc.....

// then, pull the bytes out of the array such that:
// har2 == har

Спасибо, ребята!

РЕДАКТИРОВАТЬ: Предположим, int 4 байта ...

РЕДАКТИРОВАНИЕ 2: Пожалуйста, не заботьтесь о порядке байтов ... Я буду беспокоиться о порядке байтов. Я просто хочу по-разному достичь вышеизложенного в C / C ++. Спасибо

EDIT3: Если вы не можете сказать, я пытаюсь написать класс сериализации на низком уровне ... поэтому я ищу различные стратегии для сериализации некоторых распространенных типов данных.

Ответы [ 10 ]

39 голосов
/ 06 октября 2009

Если вы не заботитесь о порядке байтов и тому подобном, memcpy сделает свое дело:

memcpy(a, &har, sizeof(har));
...
memcpy(&har2, a, sizeof(har2));

Конечно, нет никакой гарантии, что sizeof(int)==4 для какой-либо конкретной реализации (и есть реальные реализации, для которых это фактически неверно).

С этого момента написание цикла должно быть тривиальным.

22 голосов
/ 06 октября 2009

Не самый оптимальный способ, но безопасно для байтов.


int har = 0x01010101;
char a[4];
a[0] = har & 0xff;
a[1] = (har>>8)  & 0xff;
a[2] = (har>>16) & 0xff;
a[3] = (har>>24) & 0xff;
8 голосов
/ 06 октября 2009

Примечание: доступ к объединению через элемент, который не был последним назначенным, является неопределенным поведением. (предполагается, что платформа, где символы 8 битов, а целые 4 байта) Битовая маска 0xFF замаскирует один символ, поэтому

char arr[4];
int a = 5;

arr[3] = a & 0xff;
arr[2] = (a & 0xff00) >>8;
arr[1] = (a & 0xff0000) >>16;
arr[0] = (a & 0xff000000)>>24;

сделает arr [0] самым старшим байтом, а arr [3] младшим.

edit: Точно так, чтобы вы понимали хитрость & немного мудрее 'и' где as && логично 'и'. Благодаря комментариям о забытой смене.

8 голосов
/ 06 октября 2009
#include <stdio.h>

int main(void) {
    char a[sizeof(int)];
    *((int *) a) = 0x01010101;
    printf("%d\n", *((int *) a));
    return 0;
}

Имейте в виду:

Указатель на объект или неполный тип может быть преобразован в указатель на другой объект или неполный тип. Если результирующий указатель не правильно выровнен для указательный тип, поведение не определено.

8 голосов
/ 06 октября 2009
int main() {
    typedef union foo {
        int x;
        char a[4];
    } foo;

    foo p;
    p.x = 0x01010101;
    printf("%x ", p.a[0]);
    printf("%x ", p.a[1]);
    printf("%x ", p.a[2]);
    printf("%x ", p.a[3]);

    return 0;
}

Имейте в виду, что a [0] содержит LSB, а a [3] - MSB на машине с прямым порядком байтов.

7 голосов
/ 06 октября 2009

Не используйте союзы, уточняет Павел:

Это U.B., потому что C ++ запрещает доступ к любому члену профсоюза, кроме последний, который был написан. В В частности, компилятор может свободно оптимизировать назначение на int член полностью с кодом выше, так как его значение не впоследствии используется (он видит только последующее чтение для char[4] член, и не обязан предоставить любое значимое значение там). На практике g ++, в частности, известен потянув такие трюки, так что это это не просто теория. С другой стороны, используя static_cast<void*> с последующим static_cast<char*> гарантировано работа.

- Павел Минаев

4 голосов
/ 06 октября 2009

Вы также можете использовать новое размещение для этого:

void foo (int i) {
  char * c = new (&i) char[sizeof(i)];
}
2 голосов
/ 24 октября 2011

    #include <stdint.h>

    int main(int argc, char* argv[]) {
        /* 8 ints in a loop */
        int i;
        int* intPtr
        int intArr[8] = {1, 2, 3, 4, 5, 6, 7, 8};
        char* charArr = malloc(32);

        for (i = 0; i < 8; i++) {
            intPtr = (int*) &(charArr[i * 4]);
          /*  ^            ^    ^        ^     */
          /* point at      |    |        |     */
          /*       cast as int* |        |     */
          /*               Address of    |     */
          /*            Location in char array */

            *intPtr = intArr[i]; /* write int at location pointed to */
        }

        /* Read ints out */
        for (i = 0; i < 8; i++) {
            intPtr = (int*) &(charArr[i * 4]);
            intArr[i] = *intPtr;
        }

        char* myArr = malloc(13);
        int myInt;
        uint8_t* p8;    /* unsigned 8-bit integer  */
        uint16_t* p16;  /* unsigned 16-bit integer */
        uint32_t* p32;  /* unsigned 32-bit integer */

        /* Using sizes other than 4-byte ints, */
        /* set all bits in myArr to 1          */
        p8 = (uint8_t*) &(myArr[0]);
        p16 = (uint16_t*) &(myArr[1]);
        p32 = (uint32_t*) &(myArr[5]);
        *p8 = 255;
        *p16 = 65535;
        *p32 = 4294967295;

        /* Get the values back out */
        p16 = (uint16_t*) &(myArr[1]);
        uint16_t my16 = *p16;

        /* Put the 16 bit int into a regular int */
        myInt = (int) my16;

    }

1 голос
/ 18 июля 2017
char a[10];
int i=9;

a=boost::lexical_cast<char>(i)

обнаружил, что это лучший способ конвертировать char в int и наоборот.

альтернатива boost :: lexical_cast - это sprintf.

char temp[5];
temp[0]="h"
temp[1]="e"
temp[2]="l"
temp[3]="l"
temp[5]='\0'
sprintf(temp+4,%d",9)
cout<<temp;

вывод будет: hell9

0 голосов
/ 28 октября 2010
union value {
   int i;
   char bytes[sizof(int)];
};

value v;
v.i = 2;

char* bytes = v.bytes;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...