[C/C++] бинарная строка --> int

williamsmith61

Ступор.
Есть char* допустим с таким бинарным содержимым: 0x3F 0x34 0x54 0x00.
Как преобразовать это дело в int чтобы получить 0x3F345400?

ryshiy28

Если бы была бинарная строка
char a[]={0x00,0x54,0x34,0x3F};
то после присваивания
int b = *int *) a);
в переменной b будет искомое 0x3F345400

williamsmith61

Спасибо, попробую.

Elina74

Если ты уверен, что в твоем инте помещается 4 байта, пожалуйста, примитивное, зато универсальное решение:
char c[] = {0x3F, 0x34, 0x54, 0x00};
int a = c[3] + c[2]*265 + c[1]*256*256 + c[0]*256*256*256;

vall

фу как некрасиво, про бинарные сдвиги на физфаке не учат?

bleyman

Нормальный компилятор всё равно сдвиг подставит.
Но вот шестнадцатеричной записью не пользоваться - это дисреспект и фу полюбому.

erotic

+1 первонах

erotic

Ты серьезно? Тогда -2 к предыдущему посту

Elina74

Надо писать как проще. Тем более, что компилятор сам разберется.

vall

да пофиг на компилятор - выглядит некрасиво.
сдвиги всяко лучше. да и в циферках очепечатся можно, что Глюк и сделал собственно гыгыгы

mira-bella

Если бы была бинарная строка
char a[]={0x00,0x54,0x34,0x3F};
то после присваивания
int b = *int *) a);
в переменной b будет искомое 0x3F345400
на некоторых архитектурах, а на других 0x0054343F

erotic

а как быстрее:
c[0]<<8) + c[1])<<8) + c[2])<<8) + c[3]
или
c[3] + (c[2]<<8) + (c[1]<<16) + (c[0]<<24)?
Наверное, вообще вот так:
c[3] | (c[2]<<8) | (c[1]<<16) | (c[0]<<24)

banderon

Есть char* допустим с таким бинарным содержимым: 0x3F 0x34 0x54 0x00.
Как преобразовать это дело в int чтобы получить 0x3F345400?
а как быстрее:
c[0]<<8) + c[1])<<8) + c[2])<<8) + c[3]
или
c[3] + (c[2]<<8) + (c[1]<<16) + (c[0]<<24)?
Все хорошо, только порядок другой получается, надо поменять c[0]<->c[3], c[1]<->c[2].
Наверное, вообще вот так:
c[3] | (c[2]<<8) | (c[1]<<16) | (c[0]<<24)
А это вообще не работает, если c объявлено как char*. Но будет работать, если объявить как unsigned char*.
Насчет скорости выполнения: надо ставить эксперименты на конкретных машинах/компиляторах.

evgen5555

ntohl(*long*)pch

Ivan8209

> Если бы была бинарная строка
> char a[]={0x00,0x54,0x34,0x3F};
> то после присваивания
> int b = *int *) a);
> в переменной b будет искомое 0x3F345400
Не будет.
Правильный ответ дали те, кто воспользовался сложением или поразрядными "или".
, твой ответ тоже неверен (неполон): у тебя с вероятностью 1/2 или 3/4
может случаться то, что униксоиды называют SIGBUS.
Разве что будет передаваться правильный указатель.
---
...Я работаю антинаучным аферистом...

erotic

Все хорошо, только порядок другой получается, надо поменять c[0]<->c[3], c[1]<->c[2].
Шутишь? Во всех примерах c[3] не сдвигается ни на сколько, c[0] сдвигается на 24 бита. Где ошибка?
P.S. А. Заметил. Там в char* порядок не тот

evgen5555

может случаться то, что униксоиды называют SIGBUS.
Я пользуюсь SEH, так что не должно

Sebasten

Распространённых архитектур всего две, можно и дефайн какой-нить зафигачить

Ivan8209

> Распространённых архитектур всего две
Чё?
---
"Расширь своё сознание!"

mira-bella

Распространённых архитектур всего две,
да?
вот интересно узнать: какие именно две?

mira-bella

ntohl(*long*)pch
во-первых long не обязан быть ровно 4 char-а, а в распространенном случае когда он из 8-ми char-ов это выражение выходит за границу массива,
и во-вторых это выражение нарушает т.н. strict aliasing rules, и может приводить к неверному результату при наличии некоторых сильных оптимизаций, разрешенных стандартом.

Ivan8209

Последние виденные мной вопросы были связаны с HC08, ARM и 68K.
Видимо, надо выкинуть одну из этих трёх.
---
...Я работаю антинаучным аферистом...

evgen5555



во-вторых long не обязан быть ровно 4 char-а, и даже не обязан быть не менее 4 char-а (ибо char может быть более 8 бит
Примеры?

evgen5555

Хотел, кстати, написать uint32_t, но потом передумал.

Ivan8209

> Во-первых в данном случае мог бы быть уместен htonl(*long*)pch
> ибо "host to network", а не наоборот
Почему?
Я, наоборот, вижу, что по указателю находятся байты в сетевом порядке,
а в int надо получить родной, машинный.
Я не стал вдаваться в подробности, что int бывает 16-разрядным,
и четыре, как хочет того автор, октета в него просто так не влезут.
---
...Я работаю антинаучным аферистом...
P.S. А что, насильники разрешили char-у быть больше октета?

mira-bella

во-вторых long не обязан быть ровно 4 char-а, и даже не обязан быть не менее 4 char-а (ибо char может быть более 8 бит
Примеры?
любая 64-битная архитектура с компилятором gcc - sizeof(long)==8*sizeof(char) - 64 бит, и уже выражение
*long*)pch) будет читать за границей массива из четырех char-ов, что есть потенциальный segfault.

mira-bella

> Во-первых в данном случае мог бы быть уместен htonl(*long*)pch
> ибо "host to network", а не наоборот
Почему?
Я, наоборот, вижу, что по указателю находятся байты в сетевом порядке,
а в int надо получить родной, машинный.
согласен,
исправился

Ivan8209

> архитектура с компилятором gcc
Кстати о gcc.
Как он относится к выравниванию char? Выравнивает?
---
...Я работаю антинаучным аферистом...

Sebasten

Big Endian y Little Endian

bleyman

sizeof(char) тождественно равен 1.
Писать платформо-независимый код, который решает платформо-зависимую задачу - это жесть, респект Контре и всем остальным поучавствовавшим.
Если, блиа, в char* лежит ЧЕТЫРЕ БАЙТА, СИМВОЛИЗИРУЮЩИЕ СОБОЙ BIG-ENDIAN ИНТ, то, наверное, рассуждения на тему того, как бы их пошевелить на литтл-эндиан 64битной машине, имеют отчётливый привкус благородного безумия. Не, я понимаю, вдруг их такими по сети прислали, но всё же.
ЗЫ: В весьма большой части не-8086 архитектур инт двухбайтный, хаха.
ЗЗЫ: блайнду - респект =) Глюк жжот "int a = c[3] + c[2]*265 + c[1]*256*256 + c[0]*256*256*256;"

maggi14

собсна, и в х86 архитектурах встречался двухбайтный инт
в смысле, лично мне встречался несколько лет подряд

mira-bella

sizeof(char) тождественно равен 1.
разумеется, но это не означает, что char 8-битный
Писать платформо-независимый код, который решает платформо-зависимую задачу - это жесть,
это не жесть, а совершенно обычная практика
всю платформозависимость обычно нетрудно скрыть в маленьком интерфейсе, если нельзя вообще без этого обойтись и опираясь на стандарт писать кроссплатформенный код.
ЗЫ: В весьма большой части не-8086 архитектур инт двухбайтный, хаха.
и что?

mira-bella

Big Endian y Little Endian
это не две архитектуры, а 2 типа порядка байтов в числах (они действительно наиболее распространены, но тем не менее есть и другие)
а количество широко используемых архитектур исчисляется десятками

mira-bella

Если, блиа, в char* лежит ЧЕТЫРЕ БАЙТА, СИМВОЛИЗИРУЮЩИЕ СОБОЙ BIG-ENDIAN ИНТ, то, наверное, рассуждения на тему того, как бы их пошевелить на литтл-эндиан 64битной машине, имеют отчётливый привкус благородного безумия.
И с чего же это?
Речь вообще о том, как их пошевелить на любой машине.
Очевидно ни размеры целочисленных типов рабочей платформы, ни порядок байтов в них не были указаны в условии задачи, поэтому опираться можно только на положения стандарта.

vall

Если, блиа, в char* лежит ЧЕТЫРЕ БАЙТА, СИМВОЛИЗИРУЮЩИЕ СОБОЙ BIG-ENDIAN ИНТ, то, наверное, рассуждения на тему того, как бы их пошевелить на литтл-эндиан 64битной машине, имеют отчётливый привкус благородного безумия. Не, я понимаю, вдруг их такими по сети прислали, но всё же.
в косущих бинарных протоклолах типа СМБ с этим немного весело, особенно с выравниванием.
а вот на powerpc есть спец команды для реверса байтов (код из самбы)
static __inline__ uint32_t ld_le32(const uint32_t *addr)
{
uint32_t val;
__asm__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (addr "m" (*addr;
return val;
}

а вот на трёшке что-то я не помню (хз, потом может что и появилось)
или есть свап байтов в слове и слов в двойном слове?
но это изврат какой-то.
видимо клали интеловцы на ИБМ, а вот ИБМ на интелов не поклала

bleyman

Эт ещё фигня, мне тут знакомый рассказал, что у виртуальной жавамашыны литтлэндиан архитектура. И на PC, естественно, тоже. Поэтому процесс совокупления плюсовой и жавапроги с быстрым обменом бинарными данными выглядит довольно-таки мерзко.

Sebasten

а количество широко используемых архитектур исчисляется десятками
Ну так способ хранения чисел в памяти - одна из особенностей (характеристика) каждой из них, теперь представь, что по всем остальным характеристикам все широко используемые архитекруры для нас неразличимы (то есть мы переходим в одноразмерное признаковое пространство). В этом пространстве все наши архитектуры делятся на два класса:
BIg и Little Endian. Назовём всех представителей первого класса - процессорами с Биг Эндиан архитектурой, а соответсвенного второго - с Литтл. Ясно теперь тебе, что значит "Биг Эндиан Архитектруа"?

vall

Эт ещё фигня, мне тут знакомый рассказал, что у виртуальной жавамашыны литтлэндиан архитектура. И на PC, естественно, тоже. Поэтому процесс совокупления плюсовой и жавапроги с быстрым обменом бинарными данными выглядит довольно-таки мерзко.
дык у PC и есть литтл-эндиан, в чём проблема то?
странно, мне всегда казалось что у явы эндинутость максимально спрятана и соответствует хосту.

Elina74

Глюк жжот "int a = c[3] + c[2]*265 + c[1]*256*256 + c[0]*256*256*256;"
Я дико извиняюсь, можно мне не убивать себя об стену? Ты, если что, не первый, кто это заметил.

mira-bella

Ну так способ хранения чисел в памяти - одна из особенностей (характеристика) каждой из них,
именно ОДНА из них
Архитектурой все же общепринято называть гораздо большую совокупность признаков, а не один единственный, упомянутый тобой. Гораздо более определяющей характеристикой архитектуры можно считать систему команд проца (спецификация и реализация которой естественным образом определяет и порядок байтов в регистровых числах, если их вообще можно логически делить на байты систему доступа к устройствам, особенно организация оперативной памяти, и т.п.
Например, некоторые архитектуры позволяют переключать порядок байтов.
В этом пространстве все наши архитектуры делятся на два класса:
BIg и Little Endian.
а к какому из этих классов относится архитектура, у которой нет регистров больше байта?
или архитектура, у которой все регистры и адресуемые за команду ячейки памяти одинаковы и не делятся на байты, а делятся, например на 16-битные или 32-битные блоки?
или архитектура, которая может переключать порядок байтов в процессе работы?
или PDP10, у которой порядок байтов не big endian и не little endian?
Ясно теперь тебе, что значит "Биг Эндиан Архитектруа"?

что же я без тебя делал бы
так бы наверно и помер не просвещенный

agaaaa


void convert(char* source, int* dest, int int_count)
{
const int char_sz = sizeof(char) * 8;
const int mult = sizeof(int)/sizeof(char);
unsigned int *dst = dest;
unsigned char *src = source;
int i;
for(;int_count > 0; int_count--, dst++)
{
*dst = 0;
#ifdef little_endian
for(i = mult - 1; i >= 0; i--, src++)
(*dst) += (*src) << (i * char_sz);
#else
for(i = 0; i < mult; i++, src++)
(*dst) += (*src) << (i * char_sz);
#endif
}
}

Может я чего напортачил с утра, но должно быть примерно так. Остальное вроде проблемы компилятора. Я, разумется, предполагаю, что у нас числа не хранятся извратно.
Только что нашёл баг. Если sizeof возвращает не количество 8-битных байтов, то дело плохо. С другой стороны тогда Си отстойный язык и не очень-то переносимый. Или нужна ещё константа количества бит в чаре или в инте. Лучше в чаре

Sebasten

"Век живи - век учись, и всё равно дураком помрёшь"

Sebasten

В задаче уже итак указан порядок хранения байтов в source (от старшего к младшему так что никакие заморочки не нужны

#define NUM_BITS 8

unsigned int _convert(const unsigned char* source, size_t _size)
{
assert(sizeof(unsigned) >= _size);
unsigned res = 0;
for(size_t i = 0; i < _size; ++i)
{
res |= source[i] << i * NUM_BITS;
}
return res;
}

Ivan8209

> теперь представь, что по всем остальным характеристикам
> все широко используемые архитекруры для нас неразличимы
Я тебе ещё раз повторю: на большинстве архитектур
ты не считаешь невыравненные данные за одну команду.
Это будет не то же самое, что на x86: оно будет не просто медленее, оно не будет никак.
Поэтому не работает решение с ntoh*.
А представить вакуумированную сферическую лошадь я могу --- воображение позволяет.
---
...Я работаю антинаучным аферистом...

Ivan8209

> а к какому из этих классов относится архитектура, у которой нет регистров больше байта?
> или архитектура, у которой все регистры и адресуемые за команду ячейки памяти одинаковы
> и не делятся на байты, а делятся, например на 16-битные или 32-битные блоки?
Мне было бы интереснее узнать про архитектуры без (адресуемых) регистров
и с 18- и 21-разрядными ячейками оперативной памяти.
Реальные лошади в действии.
---
...Я работаю антинаучным аферистом...

Sharp

А чем тебе не подходит идея создания union из 4-х char-ов и одного int-а?

Ivan8209

> Писать платформо-независимый код, который решает платформо-зависимую задачу - это жесть
Это суровая необходимость жизни.
Когда увидишь код, который на MC68EZ328 собирает big-endian число по октетам, поймёшь.
Если не поймёшь сразу, поймёшь потом, когда более простой код грохнется.
Как ни странно, я понял сразу, где засада.
---
...Я работаю антинаучным аферистом...

erotic

Тут вообще-то тоже кроется проблема порядка байтов.

Sharp

htonl никто еще не отменял.
в общем, я почитал трэд, и не могу понять чем автора не устраивает решение

union {
char chars[4];
int number;
} test;

А дальше если надо поменять порядок, то делать это в number-е, забыв про всякие свдиги и умножения.

vall

А дальше если надо поменять порядок, то делать это в number-е, забыв про всякие свдиги и умножения.
расскажи, как ты на BE машине это сделаешь без сдвигов и умножений?

Ivan8209

> htonl никто еще не отменял.
SIGBUS тоже.
---
...Я работаю антинаучным аферистом...

williamsmith61

в общем, я почитал трэд, и не могу понять чем автора не устраивает решение
Да я сам почитал тред и охренел
Меня и мою архитектуру вполне устроило первое решение.

vall

htonl никто еще не отменял.
не везде обращает порядок байтов

Sharp

ну ладно, на Фре есть le32toh и ей подобные.
были взяты с NetBSD - должны быть и там.

vall

в линухе не нашёл.
всякая LE\BE фигня есть в glib.

Ivan8209

Дело не в этом, дело в том, что ntohl будет читать из памяти невыравненные данные,
поскольку "char" не обязан выравниваться на границу слова.
Наверное, на границу слова должно выравниваться предложенное "union",
пожалуй, тогда можно будет им воспользоваться, но только
им надо уметь правильно пользоваться.
---
...Я работаю антинаучным аферистом...
P.S. Про то, что "long" бывает подлиннее "4 chars", опять забыли.

Ivan8209

> были взяты с NetBSD - должны быть и там
Может быть и должны, но где и под какими именами?
---
...Я работаю антинаучным аферистом...

Sharp

Как признался автор данного трэда, он уже выбрал для себя решение. А мы тут продолжаем дальше спорить и красоваться друг перед другом всяческими познаниями в области переносимости и т.д.
Лучшее - враг хорошего.

Ivan8209

> Как признался автор данного трэда, он уже выбрал для себя решение.
Это малоинтересно.
> А мы тут продолжаем дальше спорить и красоваться
Тебе это не нравится?
---
...Я работаю антинаучным аферистом...

mira-bella

htonl никто еще не отменял.
в общем, я почитал трэд, и не могу понять чем автора не устраивает решение

union {
char chars[4];
int number;
} test;

А дальше если надо поменять порядок, то делать это в number-е, забыв про всякие свдиги и умножения.
Это было бы замечательное решение, но оно некорректно с точки зрения стандарта, ибо по стандарту содержимое union предсказуемо только пока используется одно из его полей, т.е. когда что-то определенное присвоено chars[], содержимое number непредсказуемо, например неизвестно где будут chars[4]: в начале number или в конце (если number больше chars[4] и вообще оптимизатор имеет право держать chars и number раздельно на каких-то участках кода.
Самое корректное решение, какое приходит в голову:

#include <limits.h> /* for CHAR_BIT */
#include <stdint.h> /* for uintmax_t */

int f(void)
{
unsigned char c[4]= {...};

#if ( UINTMAX_MAX >> CHAR_BIT*3 ) >= UCHAR_MAX

uintmax_t num = c[3] | ( (uintmax_t)c[2] << CHAR_BIT ) |
( (uintmax_t)c[1] << CHAR_BIT*2 ) | ( (uintmax_t)c[0] << CHAR_BIT*3 );

#else
# error "4-chars number will not fit in the widest integer type"
#endif
....................
}

для C90 удаляем:
#include <stdint.h>
и uintmax_t и UINTMAX_MAX заменяем на unsigned long и ULONG_MAX соответственно

agaaaa

Вообще говоря, нам пофиг на порядок в source. Нам важен порядок source'ов в dest, который и определяется дефайнами.
Чем вас не устраивает моё решение, уважаемые архитектурные эксперты?
Кстати говоря, ещё можно заменить дефайны на проверку порядка каким-нить способом. Это возможно, но, имхо, не сильно необходимо.

Sebasten

> А мы тут продолжаем дальше спорить и красоваться
Тебе это не нравится?
Ахтунг!

Sebasten

Чем вас не устраивает моё решение, уважаемые архитектурные эксперты?
Ну так оно неправильное, говорю те, что вот эта супер программа (она без умножений)
 

#include <assert.h>
#include <limits.h>
#include <stdio.h>
/*!
** \param source Указатель на кусок памяти где хранятся байты в порядке от старшего в младшему
** \param _size размер куска памяти в байтах
** \return Число, которое образуют эти байты
*/
unsigned int _convert(const unsigned char* source, size_t _size)
{
assert(sizeof(unsigned int) >= _size);
unsigned int res = 0;
for(size_t i = 0; i < _size; ++i)
{
res <<= CHAR_BIT;
res |= source[i];
}
return res;
}

int main
{
const unsigned char a[] = {0x3F, 0x34, 0x54, 0x00};
printf("%x\n", _convert(a, sizeof(a)/sizeof(a[0];
return 0;
}

будет всегда работать правильно, хоть на биг, хоть на смол, на какой хочешь архитектуре она тебе напечатает "3f345400"
 :)
Оставить комментарий
Имя или ник:
Комментарий: