Преобразование int в массив размером 4 байта char (C)
Эй, я хочу преобразовать 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
Ответы
Ответ 1
Портативный способ сделать это (гарантируя, что вы получите 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]);
Ответ 2
Вы хотите обратиться к отдельным байтам 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 для отражения значений без знака.
Ответ 3
В вашем вопросе вы заявили, что хотите преобразовать пользовательский ввод от 175 до
00000000 00000000 00000000 10101111
, который представляет собой большой порядок байтов байтов, также известный как порядок сетевых байтов.
В основном переносимый способ преобразования вашего беззнакового целого в массив без знака без знака char, как вы предположили из этого примера "175", который вы указали, будет использовать функцию C htonl()
(определенную в заголовке в системах Linux), чтобы преобразовать ваш unsigned int в порядок байтов большого endian, затем используйте memcpy()
(определенный в заголовке <string.h>
для C, <cstring>
для С++), чтобы скопировать байты в ваш char (или без знака 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.
Ответ 4
Вы можете попробовать:
void CopyInt(int value, char* buffer) {
memcpy(buffer, (void*)value, sizeof(int));
}
Ответ 5
int a = 1;
char * c = (char*)(&a); //In C++ should be intermediate cst to void*
Ответ 6
Зачем вам нужен промежуточный листинг в void * в С++
Поскольку cpp не допускает прямого преобразования между указателями, вам нужно использовать reinterpret_cast или casting для void * делает вещь.
Ответ 7
Проблема с преобразованием (причина, по которой он дает вам ffffff в конце), состоит в том, что ваше шестнадцатеричное целое (с которым вы используете и двоичный оператор с) интерпретируется как подписанное. Внесите его в целое число без знака, и все будет в порядке.
Ответ 8
An 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);
Надеюсь, что это поможет.
Ответ 9
Вы можете просто использовать memcpy
следующим образом:
unsigned int value = 255;
char bytes[4] = {0, 0, 0, 0};
memcpy(bytes, &value, 4);
Ответ 10
Я думаю, что это самое простое и более эффективное решение:
unsigned char bytes[4];
unsigned int number = 123456;
*(unsigned int*)bytes = number
Ответ 11
Проблема возникает, поскольку 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]);