Преобразование int в 4-байтовый массив символов (C) - PullRequest
63 голосов
/ 24 сентября 2010

Эй, я хочу преобразовать int, который вводится пользователем, в 4 байта, которые я назначаю массиву символов. Как это можно сделать?

Пример:

Преобразование пользовательских данных от 175 до

00000000 00000000 00000000 10101111


Проблема со всеми ответами до сих пор, преобразование 255 должно привести к 0 0 0 ff, хотя оно печатается как: 0 0 0 ffffffff

unsigned int value = 255;   

buffer[0] = (value >> 24) & 0xFF;
buffer[1] = (value >> 16) & 0xFF;
buffer[2] = (value >> 8) & 0xFF;
buffer[3] = value & 0xFF;

union {
    unsigned int integer;
    unsigned char byte[4];
} temp32bitint;

temp32bitint.integer = value;
buffer[8] = temp32bitint.byte[3];
buffer[9] = temp32bitint.byte[2];
buffer[10] = temp32bitint.byte[1];
buffer[11] = temp32bitint.byte[0];

оба результата 0 0 0 ffffffff вместо 0 0 0 ff

Просто еще один пример - 175, поскольку входное значение выводится как 0, 0, 0, ffffffaf, когда оно должно быть просто 0, 0, 0, af

Ответы [ 10 ]

130 голосов
/ 24 сентября 2010

портативный способ сделать это (гарантируя, что вы получите 0x00 0x00 0x00 0xaf везде) - использовать смены:

unsigned char bytes[4];
unsigned long n = 175;

bytes[0] = (n >> 24) & 0xFF;
bytes[1] = (n >> 16) & 0xFF;
bytes[2] = (n >> 8) & 0xFF;
bytes[3] = n & 0xFF;

Методы, использующие объединения и memcpy(), получат разные результаты на разных машинах.


Проблема связана с печатью, а не с конверсией. Я предполагаю, что вы используете char вместо unsigned char, и вы используете такую ​​строку для печати:

printf("%x %x %x %x\n", bytes[0], bytes[1], bytes[2], bytes[3]);

Когда любые типы, более узкие, чем int, передаются в printf, они повышаются до int (или unsigned int, если int не может содержать все значения исходного типа). Если на вашей платформе подписано char, то 0xff, вероятно, не вписывается в диапазон этого типа, и вместо этого устанавливается значение -1 (которое имеет представление 0xff на машине с дополнением 2s).

-1 повышен до int и имеет представление 0xffffffff как int на вашем компьютере, и это то, что вы видите.

Ваше решение - либо использовать unsigned char, либо привести к unsigned char в выражении printf:

printf("%x %x %x %x\n", (unsigned char)bytes[0],
                        (unsigned char)bytes[1],
                        (unsigned char)bytes[2],
                        (unsigned char)bytes[3]);
14 голосов
/ 24 сентября 2010

Вы хотите обратиться к отдельным байтам 32-битного int?Одним из возможных методов является объединение:

union
{
    unsigned int integer;
    unsigned char byte[4];
} foo;

int main()
{
    foo.integer = 123456789;
    printf("%u %u %u %u\n", foo.byte[3], foo.byte[2], foo.byte[1], foo.byte[0]);
}

Примечание: исправлено printf для отображения значений без знака.

6 голосов
/ 21 января 2016

В своем вопросе вы указали, что хотите преобразовать пользовательский ввод из 175 в 00000000 00000000 00000000 10101111, то есть порядковый номер байта , также известный как сетевой порядок байтов .

A в основном переносимый способ преобразования вашего целого без знака в массив без знака с прямым порядком байтов, как вы и предполагали из приведенного вами примера "175", заключался бы в использовании функции C htonl()(определено в заголовке <arpa/inet.h> в системах Linux) для преобразования вашего unsigned int в порядок байтов с прямым порядком байтов, затем используйте memcpy() (определено в заголовке <string.h> для C, <cstring> для C ++), чтобы скопировать байты вваш массив char (или unsigned char).

Функция htonl() принимает 32-разрядное целое число без знака в качестве аргумента (в отличие от htons(), который принимает без знака)16-разрядное целое число) и преобразует его в сетевой байтовый порядок из байтового порядка хоста (отсюда аббревиатура Host TO Network Long, вместо Host TO Network Short для htons), возвращая результат в виде 32-разрядного целого числа без знака.Целью этого семейства функций является обеспечение того, чтобы все сетевые соединения происходили в порядке байтов с прямым порядком байтов, чтобы все машины могли взаимодействовать друг с другом через сокет без проблем с порядком байтов.(Кроме того, для машин с прямым порядком байтов функции htonl(), htons(), ntohl() и ntohs(), как правило, компилируются так, чтобы они были просто 'no op', потому что байты не нужно переворачиватьпрежде чем они будут отправлены или получены из сокета, поскольку они уже находятся в правильном порядке байтов)

Вот код:

#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>

int main() {
    unsigned int number = 175;

    unsigned int number2 = htonl(number);
    char numberStr[4];
    memcpy(numberStr, &number2, 4);

    printf("%x %x %x %x\n", numberStr[0], numberStr[1], numberStr[2], numberStr[3]);

    return 0;
}

Обратите внимание, что, как сказал caf, вы должныпечатать символы как без знака , используя спецификатор формата printf %x.

Приведенный выше код печатает 0 0 0 af на моем компьютере (компьютере x86_64, который использует порядок байтов с прямым порядком байтов), которыйшестнадцатеричное для 175.

2 голосов
/ 24 сентября 2010

Вы можете попробовать:

void CopyInt(int value, char* buffer) {
  memcpy(buffer, (void*)value, sizeof(int));
}
1 голос
/ 17 июня 2013

Зачем вам нужно промежуточное приведение к void * в C ++. Поскольку cpp не разрешает прямое преобразование между указателями, вам нужно использовать reinterpret_cast или приведение к void *.

0 голосов
/ 21 ноября 2018

Вы можете просто использовать memcpy следующим образом:

unsigned int value = 255;
char bytes[4] = {0, 0, 0, 0};
memcpy(bytes, &value, 4);
0 голосов
/ 31 октября 2017

int эквивалентно uint32_t и char до uint8_t.

Я покажу, как я разрешил соединение клиент-сервер, отправив фактическое время (4 байта, отформатированное в эпоху Unix) в 1-битный массив, а затем перестроил его на другой стороне. (Примечание: протокол должен был отправить 1024 байта)

  • Клиентская сторона

    uint8_t message[1024];
    uint32_t t = time(NULL);
    
    uint8_t watch[4] = { t & 255, (t >> 8) & 255, (t >> 16) & 255, (t >> 
    24) & 255 };
    
    message[0] = watch[0];
    message[1] = watch[1];
    message[2] = watch[2];
    message[3] = watch[3];
    send(socket, message, 1024, 0);
    
  • Серверная сторона

    uint8_t res[1024];
    uint32_t date;
    
    recv(socket, res, 1024, 0);
    
    date = res[0] + (res[1] << 8) + (res[2] << 16) + (res[3] << 24);
    
    printf("Received message from client %d sent at %d\n", socket, date);
    

Надеюсь, это поможет.

0 голосов
/ 25 февраля 2016

Проблема с преобразованием (причина, по которой он дает вам ffffff в конце) заключается в том, что ваше шестнадцатеричное целое число (с которым вы используете & двоичный оператор) интерпретируется как подписанное.Приведите его к целому числу без знака, и все будет в порядке.

0 голосов
/ 07 июля 2014

Проблема возникает из-за того, что unsigned char - это 4-байтовое число, а не 1-байтовое число, как многие думают, поэтому измените его на

union {
unsigned int integer;
char byte[4];
} temp32bitint;

и приведение во время печати, чтобы предотвратить повышение до 'int' (что C делает по умолчанию)

printf("%u, %u \n", (unsigned char)Buffer[0], (unsigned char)Buffer[1]);
0 голосов
/ 24 сентября 2010
int a = 1;
char * c = (char*)(&a); //In C++ should be intermediate cst to void*
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...