LINUX.ORG.RU

Преобразование bytes в число

 


0

3

Есть пример кода:

typedef union _TypeUn{
__int32 i;
unsigned char Byte[4];
} TypeUn;


void ConvertByteToInt(char * bytes, char * StrInt)
{
 TypeUn tc;
 char znak = ' ';
 tc.Byte[0] = bytes[0];
 tc.Byte[1] = bytes[1];
 tc.Byte[2] = bytes[2];
 tc.Byte[3] = bytes[3];

 int h,m,s,f;
 if( tc.i < 0 )
 {
   znak = '-';
   tc.i = abs(tc.i);
 }
 else
   znak = '+';

 tc.i >>= 2;

 ConvertToTime(tc.i,h,m,s,f);

 sprintf(StrInt,"%c%02d:%02d:%02d:%02d",znak,h,m,s,f);
}
Я не пойму как это работает - как из массива bytes получается целое число ?



Последнее исправление: Jopich (всего исправлений: 1)

как из массива bytes получается целое число ?

union. Байты лежат на том же месте, где и int поле. Трюк с записью и чтением разных полей union работает в GCC, но по стандарту работать не обязан.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

но по стандарту работать не обязан.

Почему? Это же и есть то, для чего был создан union. Или я чего-то не знаю?

Kroz ★★★★★
()
Ответ на: комментарий от Kroz

Не просто не обязан, это undefiened bahavior.

Из union можно взять только то что туда положено (положили число, взять можно только число, байты трогать нельзя). union был создан ровно для этого (хранить объект одного из заданных типов без оверхеда), не для хаков с преобразованием типов бинарных данных.

slovazap ★★★★★
()
Последнее исправление: slovazap (всего исправлений: 1)
Ответ на: комментарий от i-rinat

О каком преобразовании спрашиваете?

Трюк в сабже архитектурно-зависим. Зависит от endianness архитектуры. По-хорошему нужно юзать ntohl(), htonl() и т. п.

Andrey_Utkin ★★
()
Ответ на: комментарий от Andrey_Utkin

О каком преобразовании спрашиваете?

преобразовать что-то крупнее байт в байты и наоборот.

По-хорошему нужно юзать ntohl(), htonl() и т. п.

В glibc есть htobe32(), htole32(), htobe64() и обратные.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

В glibc есть htobe32(), htole32(), htobe64() и обратные.

И ещё много чего. И что?

Andrey_Utkin ★★
()
Ответ на: комментарий от i-rinat

Но для double, скорее всего, нет.

Так точно, не подходит.

ntohl(), htonl() - для лонгов, у ТС - int h,m,s,f; А нужны даблы?

(там надо складывать(раскусывать) битовыми & | << , у float не по границе байт)

anonymous
()
Ответ на: комментарий от anonymous

А нужны даблы?

Решил заодно спросить о проблеме вообще, то есть десериализация любого примитивного типа. Я знаю способ через memcpy. Но вдруг есть ещё способы?

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Если код собирается под кокретную архитектуру - то можно и union использовать. Или битовую арифметику, но с гранулярность не по биту, а покрупнее. (uint32_t)byte[0]<<24 | (uint32_t)byte[1]<<16 | (uint32_t)byte[2]<<8 | byte[3]

vromanov ★★
()
Ответ на: комментарий от i-rinat

Гм спасибо. А мне надо эти цифры получать в python. Если я правильно понимаю нужно использовать вот это:

classmethod int.from_bytes(bytes, byteorder, *, signed=False)

    Return the integer represented by the given array of bytes.
    >>>

    >>> int.from_bytes(b'\x00\x10', byteorder='big')
    16
    >>> int.from_bytes(b'\x00\x10', byteorder='little')
    4096
    >>> int.from_bytes(b'\xfc\x00', byteorder='big', signed=True)
    -1024
    >>> int.from_bytes(b'\xfc\x00', byteorder='big', signed=False)
    64512
    >>> int.from_bytes([255, 0, 0], byteorder='big')
    16711680
Только вот какой вариант byteorder и signed ?

Jopich
() автор топика
Ответ на: комментарий от i-rinat

Если не в сеть (не надо подстраиваться под стандарт), то так:

#include <stdio.h>
#define N sizeof(double)
int main()
{
    double a = 0, b = 543.21;
    char s[N + 1];

    *((double *) s) = b;
    a = (*((double *) s));
    printf("%f %f\n", a, b);
    return 0;
}
N бывает разный: на atmega-x 32, не пентиумах >~10лет назад 48.

anonymous
()
Ответ на: комментарий от anonymous

N бывает разный: на atmega-x 32, не пентиумах >~10лет назад 48.

Поправочка: это в битах. Т.е. 32=4байта, 48=6байт.

anonymous
()
Ответ на: комментарий от slovazap

И где тут UB? Стандарт обещает, что поля union лежат по одному адресу. Поведение pragma pack также известно и детерминировано.

vromanov ★★
()
Ответ на: комментарий от vromanov

И где тут UB?

Стандарт разрешает ровно один случай чтения из union не того что туда было записано

[Note: One special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence (9.2), and if an object of this standard-layout union type contains one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of standard-layout struct members; see 9.2. — end note]

Стандарт обещает, что поля union лежат по одному адресу

И что?

Поведение pragma pack также известно и детерминировано

Лол, pragma pack вообще в стандарт не входит.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

union был создан ровно для этого (хранить объект одного из заданных типов без оверхеда)

4.2

Union был создан именно для того, что в ОП-посте. Но кросплатформенно это не описать, поэтому в стандарте этой логики нет и не будет.

LamerOk ★★★★★
()
Ответ на: комментарий от slovazap

Стандарт разрешает ровно один случай чтения из union не того что туда было записано

6.5.2.3.3


95) If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.

Laz ★★★★★
()
Ответ на: комментарий от slovazap

Никогда нельзя, это UB.

Ну, сделай барьер памяти на запись между записью одного типа и чтением другого и чтобы это UB стало действительно undefined создателям компилятора придется очень постараться. Ведь, если знаешь, как работает компилятор, то UB довольно прозрачная вещь (а если не знаешь, то что ты делаешь в профессии).

anonymous
()
Ответ на: комментарий от slovazap

UB - это всегда UB, запомните это раз и навсегда.

Только задротов-теоретиков. Практики делают стабильно работающий код на нужных архитектурах, остальные их не интересуют. Если какой-нибудь солярис студио по-своему откомпилирует код, который нормально работает под gcc и MsVc, то это трудности той платформы. А если кому-то из заказчиков упрется именно эта такая платформа, то он получит отдельный счет за ее поддержку и особые условия, после чего начнет думать более разумно.

P.S. Интересно, что ты будешь делать со своим фанатизмом, когда потребуется поддерживать платформу, которая не совсем соответствует стандартам... Потому что выбор будет «между сделать чтобы работало» и «сделать по стандарту».

anonymous
()
Ответ на: комментарий от vromanov

И где тут UB?

Компилятор может закешировать записываемое значение (т.е. не сохранять в память), а читать, что там сохранено. Может быть, конкретно в этом примере такое не возможно, но при записи и чтении из union, вполне может быть.

anonymous
()
Ответ на: комментарий от anonymous

Интересно, что ты будешь делать со своим фанатизмом

Это не фанатизм, а единственный разумный подход. А вы мало того что анонимус, так еще и говнокодер.

Deleted
()
Ответ на: комментарий от anonymous

Только задротов-теоретиков. Практики делают стабильно работающий код на нужных архитектурах, остальные их не интересуют. Если какой-нибудь солярис студио по-своему откомпилирует код, который нормально работает под gcc и MsVc, то это трудности той платформы.

Это надо в золотую рамку как эталон ламера. «Практики» такие у нас двор метут.

slovazap ★★★★★
()
Ответ на: комментарий от anonymous

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

И сменит исполнителя.

FeyFre ★★★★
()
Ответ на: комментарий от anonymous

Может так:

int i;
unsigned char b[sizeof(i)];

i=(*((int *)b));
Зачем вызов memcpy для мелких типов, известных компилятору ?

anonymous
()
Ответ на: комментарий от anonymous

Зачем вызов memcpy для мелких типов, известных компилятору?

Чтобы твой код гарантированно работал, нужно в ключи добавлять -fno-strict-aliasing.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Не понял причину. Пересечение в памяти i и b или другая ? (Пересечение - фигня, т.к. укладка в i происходит за одну пересылку из регистра в память.)

anonymous
()
Ответ на: комментарий от anonymous

как работает компилятор

Завтра он начнёт работать «по-другому», туда всунут какую-нибудь оптимизацию, основанную на UB, — и всё.

https://habrahabr.ru/post/230777/

anonymous
()
Ответ на: комментарий от anonymous

(там надо складывать(раскусывать) битовыми & | << , у float не по границе байт)

qulinxao, зачем разлогинился?

anonymous
()
Ответ на: комментарий от slovazap

Код вполне сишный, а тег не увидел. Тогда полностью поддерживаю.

Laz ★★★★★
()
Ответ на: комментарий от Jopich

А что означает эта операция в C++ синтаксисе ?

Она означает tc.i = tc.i >> 2;, то есть сдвиг вправо. (Как и в питоне, кстати). Если поле i имеет тип со знаком, и там лежит отрицательное число, операция implementation-defined.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

О подобрал.

int.from_bytes(line, byteorder="little",signed=True) >> 2
Остался вопрос: byteorder, signed - это определяется на уровне как данное число занесено в бинарный формат ?

Jopich
() автор топика
Ответ на: комментарий от Jopich

byteorder

Почитай про little endian, big endian. Без этого дальше будет трудно.

signed

Почитай про представление чисел в двоичной системе. И про представление отрицательных чисел.

i-rinat ★★★★★
()
Ответ на: комментарий от Jopich

Слушай, без обид. По косвенным оценкам тебе больше 30, ближе к 40. Заканчивал мехмат, работаешь программистом. Как вообще получилось, что для тебя поняти byte order и signed почти ничего не значат? Как? Как мимо этого можно было вообще пройти?

i-rinat ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.