Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > 4х байтное целое число записать в char[4]


Автор: relok 28.11.2010, 17:55
есть большое число (999999999 к примеру)
можно ли его двоичное представление красиво записать в char массив?

то есть к примеру число 4059099376 
(bin=11110001 11110000 11110000 11110000)
записать в char msg[4] ?
msg[0] будет равно соответственно 11110001 
и так далее

информатикой не занимался, => на ум приходит только брать первый байт, переводить в десятичное и его кидать в msg[0], и так далее

Автор: WhKitten 28.11.2010, 18:11
Если я правильно понял задачу:
Код

bool le() // true if little-endian
{
    int test = 1;
    return *(reinterpret_cast<char *>(&test)) == 1;
}

int main()
{
    unsigned int n = 4059099376U;
    unsigned char s[sizeof(n)];

    unsigned char *p = reinterpret_cast<unsigned char *>(&n);
    if (le())
        for (int i=sizeof(n)-1; i>=0; --i) s[i] = *p++;
    else
        for (int i=0; i<sizeof(n); ++i) s[i] = *p++;
}

Автор: relok 28.11.2010, 18:14
мне как новичку нифига не понятно)
сделал так:
tmp[32] - массив из нулей и единиц, который нужно разбить на 4 байта
на выходе - ch[4] , 4 числа от 0 до 255

for(i=0;i<4;i++)
    {
        ch[i]=0;
        k=128;
        for(j=0+i*8;j<8+i*8;j++)
        {
            ch[i]+=tmp[j]*k;
            k=k/2;
        }
    }

Автор: WhKitten 28.11.2010, 18:24
Мой пример запишет в массив s, числа: 241 240 240 240. Собственно 241 и есть 11110001, а 240 есть 11110000.
Функция le, нужна, чтобы убедится, что первыми идут младшие байты числа в памяти.

Автор: relok 28.11.2010, 18:35
а что значит unsigned char *p = reinterpret_cast<unsigned char *>(&n);?
а именно reinterpret_cast

Автор: WhKitten 28.11.2010, 18:40
Преобразует один тип указателя к другому без каких либо проверок. Т.е &n это указатель на unsigned int, берём тот же адрес (тот же указатель), но теперь считаем, что он указывает на unsigned char и присваиваем его p. А далее цикл. Если int 32-х битный, sizeof(n) вернёт 4, и мы запишем 4 байта в массив char'ов.
*p++, сначал берёт значение char по указателю, а затем увеличивает его на размер типа, на который указывает указатель, т.е на sizeof(char)==1.

Автор: Леопольд 28.11.2010, 19:28
Код
#include <iostream>

int main()
{
   union
   {
      unsigned i;
      unsigned char c[sizeof(unsigned)];
   };

   i = 0xFFFFFFFF;
   std::cout << std::hex << (unsigned)c[0] << (unsigned)c[1] << (unsigned)c[2] << (unsigned)c[3] << std::endl;

   return 0;
}
http://codepad.org/j0x3N8RX

Автор: WhKitten 28.11.2010, 19:52
Цитата(Леопольд @  28.11.2010,  19:28 Найти цитируемый пост)
http://codepad.org/j0x3N8RX

В Windows для i = 0x1FFFFFFF программа выдаст FFFFFF1F, а на MacOS может выдать 1FFFFFFF smile

Автор: Леопольд 28.11.2010, 22:09
WhKitten, э... и что, сложно сделать std::reverse, или просто пройти в оbратном порядке? Я просто показал что не оbязательно по bайтику каждое число переbирать... А когда у него bудет другой результат на другой платформе, он узнает что есть little endian и big endian.

Автор: cardinal 28.11.2010, 22:22
Цитата(relok @  28.11.2010,  15:55 Найти цитируемый пост)
есть большое число (999999999 к примеру)
можно ли его двоичное представление красиво записать в char массив?

Ниодного "красиво" я пока в теме не увидел, а точнее просто ужаснулся что тут увидел...
Цитата(relok @  28.11.2010,  15:55 Найти цитируемый пост)
то есть к примеру число 4059099376 
(bin=11110001 11110000 11110000 11110000)
записать в char msg[4] ?



Вот псевдокод (допишите сам):
Код

i = 4059099376;
msg[3] = i & 0x000000FF;
msg[2] = (i & 0x0000FF00) >> 8;
msg[1] = (i & 0x00FF0000) >> 16;
msg[0] = (i & 0xFF000000) >> 24;

Автор: cardinal 28.11.2010, 22:37
Или вот
http://codepad.org/NTiARQaR

(раз уж Леопольд такой интересный ресурс показал)

Автор: Леопольд 28.11.2010, 22:48
cardinal, это слишком переносимый вариант. Теперь человек не почувствует "на сеbе" разницу в порядке bайт. smile

Автор: sQu1rr 28.11.2010, 23:15
Цитата(Леопольд @  28.11.2010,  22:48 Найти цитируемый пост)
cardinal, это слишком переносимый вариант.

Неужели так плохо?  smile 

Автор: mrbrooks 29.11.2010, 09:48
а как же memcpy?

Код

int val = 1024;
const unsigned char size = sizeof(int);
unsigned char buf[size];
memcpy(buf, &val, size);


Добавлено через 4 минуты и 27 секунд
ха. кстати пришла такая мысля:

Код

template<typename T>
union Fuck
{
   T value;
   unsigned char buf[sizeof(T)];
}


Добавлено через 5 минут и 30 секунд
хотя Леопольд был раньше. лол.

Автор: baldina 29.11.2010, 10:00
Цитата(mrbrooks @  29.11.2010,  09:48 Найти цитируемый пост)
а как же memcpy?

а как же operator=() ?

Код

int val;
unsigned char s[sizeof(val)];
*(int*)s = val;

Автор: mrbrooks 29.11.2010, 10:02
Цитата(baldina @  29.11.2010,  10:00 Найти цитируемый пост)
а как же operator=() ?

о!

Автор: cardinal 29.11.2010, 10:26
Вы сделайте .асм листинг для последних трех предложений и посмотрим, что элегантней (мне например очень интересно) smile memcpy думаю отпадает (вызов функции, операции со стэком). Что делает компилятор с конструкцией union не знаю. Оператор () тоже. В смысле во что это компилируется не знаю.

Автор: azesmcar 29.11.2010, 10:31
Цитата(baldina @  29.11.2010,  10:00 Найти цитируемый пост)
а как же operator=() ?

а как же alignment?

Автор: baldina 29.11.2010, 10:47
Цитата

а как же alignment?

да никак. непричем он

Автор: azesmcar 29.11.2010, 10:53
Цитата(baldina @  29.11.2010,  10:47 Найти цитируемый пост)
да никак. непричем он 

Код

int val;
unsigned char s[sizeof(val)];
*(int*)s = val;

тут должна быть проблема, нет гарантии, что
Код

unsigned char s[sizeof(val)];

адрес s сможет разместить int
можно так
Код

unsigned char *s = new unsigned char[sizeof(val)];

оператор new должен вернуть указатель, способный разместить любой тип.

если я правильно помню такой код вызывал проблемы на SunOS.
Кто может проверить?

Автор: baldina 29.11.2010, 11:33
Цитата

нет гарантии, что ... адрес s сможет разместить int

что Вы имеете в виду?

Добавлено через 1 минуту и 51 секунду
особенно интересно в связи с  alignment

Автор: baldina 29.11.2010, 11:54
azesmcar, понял. вопрос снят  smile 

Автор: azesmcar 29.11.2010, 13:04
Цитата(baldina @  29.11.2010,  11:54 Найти цитируемый пост)
azesmcar, понял. вопрос снят   

 smile все равно отвечу для других интересующихся.
Цитата

Object types have alignment requirements (3.9.1, 3.9.2). The alignment of a complete object type is an
implementation-defined integer value representing a number of bytes; an object is allocated at an address
that meets the alignment requirements of its object type.

некоторые системы имеют требования к размещению типов. Например так: int должен размещаться по адресу, который делится без остатка на 4. Следовательно грубый cast адреса и размещение в нем типа int может нарушить это требование, отсюда и проблемы переносимости. Стандарт гарантирует, что оператор new вернет адрес, который (не знаю как первести) properly aligned для хранения объекта любого типа (этим занимается сама система).
Цитата

The pointer returned shall be suitably aligned so that it can be converted to a
pointer of any complete object type and then used to access the object or array in the storage allocated (until
the storage is explicitly deallocated by a call to a corresponding deallocation function).

а для стековых объектов такой гарантии нет.
В Loki Александреску использовал трюк с union-ом max_align, но Саттер вроде писал, что это не 100% переносимо, хотя судя по тому, что он не привел примера, эта непереносимость скорее всего проявляется на сферическом компиляторе в вакууме smile 
http://www.gotw.ca/gotw/028.htm

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)