Как преобразовать из целого числа в unsigned char в C, учитывая целые числа больше 256?
В рамках моего курса CS мне были даны некоторые функции для использования. Одна из этих функций берет указатель на беззнаковые символы для записи некоторых данных в файл (я должен использовать эту функцию, поэтому я не могу просто сделать свою собственную встроенную функцию, которая работает по-другому, кстати). Мне нужно написать массив целых чисел, значения которых могут быть до 4095, используя эту функцию (которая принимает только беззнаковые символы).
Однако правильно ли я считаю, что беззнаковый символ может иметь максимальное значение только 256, поскольку его длина составляет 1 байт? Поэтому мне нужно использовать 4 знака без знака для каждого целого числа? Но приведение не работает с большими значениями для целого числа. У кого-нибудь есть идеи, как лучше всего преобразовать массив целых чисел в беззнаковые символы?
7 ответов
Обычно беззнаковый символ содержит 8 битов с максимальным значением 255. Если вы хотите знать это для вашего конкретного компилятора, распечатайте CHAR_BIT и UCHAR_MAX из <limits.h>
Вы можете извлечь отдельные байты 32-битного целого,
#include <stdint.h>
void
pack32(uint32_t val,uint8_t *dest)
{
dest[0] = (val & 0xff000000) >> 24;
dest[1] = (val & 0x00ff0000) >> 16;
dest[2] = (val & 0x0000ff00) >> 8;
dest[3] = (val & 0x000000ff) ;
}
uint32_t
unpack32(uint8_t *src)
{
uint32_t val;
val = src[0] << 24;
val |= src[1] << 16;
val |= src[2] << 8;
val |= src[3] ;
return val;
}
Беззнаковый символ обычно имеет значение 1 байт, поэтому вы можете разложить любой другой тип на массив беззнаковых символов (например, для 4-байтового типа int вы можете использовать массив из 4 беззнаковых символов). Ваше упражнение, вероятно, о дженериках. Вы должны записать файл как двоичный файл, используя функцию fwrite(), и просто записывать в файл байт за байтом.
В следующем примере следует записать число (любого типа данных) в файл. Я не уверен, сработает ли это, так как вы заставляете приведение к unsigned char * вместо void *.
int homework(unsigned char *foo, size_t size)
{
int i;
// open file for binary writing
FILE *f = fopen("work.txt", "wb");
if(f == NULL)
return 1;
// should write byte by byte the data to the file
fwrite(foo+i, sizeof(char), size, f);
fclose(f);
return 0;
}
Я надеюсь, что приведенный пример, по крайней мере, дает вам отправную точку.
Похоже, что вы действительно хотите сделать, это вызвать sprintf, чтобы получить строковое представление ваших целых чисел. Это стандартный способ преобразования числового типа в его строковое представление. Что-то вроде следующего может помочь вам начать:
char num[5]; // Room for 4095
// Array is the array of integers, and arrayLen is its length
for (i = 0; i < arrayLen; i++)
{
sprintf (num, "%d", array[i]);
// Call your function that expects a pointer to chars
printfunc (num);
}
Если вам нужно написать массив целых чисел, просто преобразуйте массив в указатель на символ, а затем пропустите массив.
int main()
{
int data[] = { 1, 2, 3, 4 ,5 };
size_t size = sizeof(data)/sizeof(data[0]); // Number of integers.
unsigned char* out = (unsigned char*)data;
for(size_t loop =0; loop < (size * sizeof(int)); ++loop)
{
MyProfSuperWrite(out + loop); // Write 1 unsigned char
}
}
Теперь люди упомянули, что 4096 поместится в меньшем количестве бит, чем нормальное целое число. Наверное, правда. Таким образом, вы можете сэкономить место и не записывать старшие биты каждого целого числа. Лично я думаю, что это не стоит усилий. Дополнительный код для записи значения и обработки входящих данных не стоит той экономии, которую вы бы получили (возможно, если бы данные были размером с библиотеку конгресса). Правило одно: выполняйте как можно меньше работы (ее легче поддерживать). Правило два оптимизировать, если спросить (но сначала спросите, почему). Вы можете сэкономить место, но это будет стоить времени обработки и затрат на обслуживание.
Да, ты прав; символ / байт допускает только до 8 различных битов, так что это 2^8 различных чисел, от нуля до 2^8 - 1 или от нуля до 255. Сделайте что-то подобное, чтобы получить байты:
int x = 0;
char* p = (char*)&x;
for (int i = 0; i < sizeof(x); i++)
{
//Do something with p[i]
}
(Это не официально C из-за порядка объявления, но как бы там ни было... это более читабельно.:))
Обратите внимание, что этот код может быть не переносимым, так как он зависит от внутренней памяти процессора int
,
Часть назначения: integers whose values can be up to 4095 using this function (that only takes unsigned chars
должен дать вам огромный намек. 4095 без знака - 12 бит.
Вы можете хранить 12 бит в 16 бит short
, но это несколько расточительно - вы используете только 12 из 16 битов короткого. Поскольку при преобразовании символов вы имеете дело с более чем 1 байтом, вам, возможно, придется иметь дело с порядком байтов результата. Самый простой.
Вы также можете использовать битовое поле или некоторую упакованную двоичную структуру, если вас беспокоит пространство. Больше работы.
Без информации о функции, которую вы должны использовать относительно ее аргументов, возвращаемого значения и семантики (то есть определения ее поведения), трудно ответить. Одна возможность:
Дано:
void theFunction(unsigned char* data, int size);
затем
int array[SIZE_OF_ARRAY];
theFunction((insigned char*)array, sizeof(array));
или же
theFunction((insigned char*)array, SIZE_OF_ARRAY * sizeof(*array));
или же
theFunction((insigned char*)array, SIZE_OF_ARRAY * sizeof(int));
Все из которых передаст все данные theFunction()
, но будет ли чем-то иметь смысл, будет зависеть от того, что theFunction()
делает.