Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.78/37: Рейтинг темы: голосов - 37, средняя оценка - 4.78
49 / 25 / 2
Регистрация: 09.06.2008
Сообщений: 227
1

Как массив char[4] перевести в unsigned int?

06.04.2012, 21:33. Просмотров 7740. Ответов 57
Метки нет (Все метки)

Есть массив из 4х char символов (4-е байта), нужно его перевести в unsigned int.
Я сделал втупую:
C++
1
2
3
4
5
6
7
        unsigned int B=0;
        long Ex = 256 * 256 * 256;
        for (int i=0; i<4; i++)
        {
                B8 += t[i] * Ex;
                Ex /= 256;
         }
Можно ли это как-то упростить?.. а то уж слишком некрасиво, долго и программу засоряет...

Я мыслю так, т.к. обе переменные (и 4-е char'a, и int) 4-х байтовые, то появилось предположение, что можно, как-нибудь, например, обратиться к char-массиву, сразу записав его в переменную int не преобразовывая?..
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
06.04.2012, 21:33
Ответы с готовыми решениями:

Перевести long long unsigned int в массив char
Подскажите, пожалуйста, как превратить число типа long long unsigned int в массив символов? Каждый...

Надо перевести переменную типа unsigned char* в signed int и обратно
у меня есть переменная типа unsigned char*, мне нужно перевести ее в signed int , провести...

Как перевести массив int в массив char
Как перевести массив int в массив char нужна помощь

Сделать преобразование unsigned char в char, а затем типу int
Здраствуйте, есть вопрос: Число представлено двумя полями: типа long для рублей и unsigned char -...

57
236 / 227 / 58
Регистрация: 27.10.2011
Сообщений: 249
06.04.2012, 21:52 2
Лучший ответ Сообщение было отмечено как решение

Решение

C++
1
2
char ch[4] = {'a', 'b', 'c', 'd'};
int i = *(int *)ch;
3
12 / 10 / 1
Регистрация: 04.04.2012
Сообщений: 29
07.04.2012, 10:26 3
Лучший ответ Сообщение было отмечено как решение

Решение

Sergey-K красиво!

C++
1
2
3
4
5
 char t[4] ={0x04,0x03,0x02,0x01};
 int ex=0;
 
 for(int i=0;i<4;i++)
 ex+=(int)t[i]<<(i<<3);
Добавлено через 12 часов 30 минут
И еще:
C++
1
2
3
4
5
union
{
char t[4];
int i;
} number = {'a','b','c','d'};
3
Evg
Эксперт CАвтор FAQ
21101 / 8118 / 628
Регистрация: 30.03.2009
Сообщений: 22,441
Записей в блоге: 30
07.04.2012, 12:56 4
При этом надо понимать, что код из поста 2 и код с union'ом из поста 3 будут работать только на little-endian машинах. Код из поста 2 надёжно будет работать только на машинах, в которых разрешены невыровненные обращения в память. Intel'овские процессоры удовлетворяют обоим критериям, а потому для "домашнего" использования или для программы, которая будет работать исключительно на Intel'е это канает, но в общем случае - нет
2
49 / 25 / 2
Регистрация: 09.06.2008
Сообщений: 227
09.04.2012, 11:52  [ТС] 5
Цитата Сообщение от Evg Посмотреть сообщение
При этом надо понимать, что код из поста 2 и код с union'ом из поста 3 будут работать только на little-endian машинах. Код из поста 2 надёжно будет работать только на машинах, в которых разрешены невыровненные обращения в память. Intel'овские процессоры удовлетворяют обоим критериям, а потому для "домашнего" использования или для программы, которая будет работать исключительно на Intel'е это канает, но в общем случае - нет
Спасибо, для меня этот вопрос важен.
Я так понял, что little-endian используется не только на интеловских процессорах, а вообще на архитектуре 86?
p.s. Тогда, правильно ли я понимаю, что код из поста 2 всегда будет работать, если прога запущена из-под XP? (Запуск эмулятора XP я не рассматриваю).
0
Evg
Эксперт CАвтор FAQ
21101 / 8118 / 628
Регистрация: 30.03.2009
Сообщений: 22,441
Записей в блоге: 30
09.04.2012, 12:40 6
Цитата Сообщение от prosto_lynx Посмотреть сообщение
Я так понял, что little-endian используется не только на интеловских процессорах, а вообще на архитектуре 86?
Словом "Intel" я называл архитектуру процессора. Т.е. это все процессоры x86, x64_64, не важно кем произведённые (Intel'ом, AMD, может кто-то ещё выпускает)

Цитата Сообщение от prosto_lynx Посмотреть сообщение
p.s. Тогда, правильно ли я понимаю, что код из поста 2 всегда будет работать, если прога запущена из-под XP? (Запуск эмулятора XP я не рассматриваю).
Да. Причём независимо от того, реальная это машина или эмулятор.
1
-1 / 4 / 0
Регистрация: 12.06.2017
Сообщений: 60
12.06.2017, 10:39 7
А можно расшифровку способа №1 в 3 посте? его эффективность зависит от процессора?

Добавлено через 3 часа 33 минуты
По зрелом размышлении удалось на основе поста №3 сделать вот такую функцию
C++
1
2
3
4
5
6
7
8
9
unsigned int uintof4b(char buffer[4])
{
    unsigned int x = 0;
    for (int i = 0; i < 4; i++)
    {
        x += (unsigned char)buffer[3 - i] << (i << 3);
    }
    return x;
}
работает с учетом того, что могут встретиться отрицательные charы и возвращает беззнаковый результат. Странно, что для такой простой задачи приходится изобретать такой сложный костыль
0
Evg
Эксперт CАвтор FAQ
21101 / 8118 / 628
Регистрация: 30.03.2009
Сообщений: 22,441
Записей в блоге: 30
12.06.2017, 16:19 8
Цитата Сообщение от bugaboo Посмотреть сообщение
Странно, что для такой простой задачи приходится изобретать такой сложный костыль
Просто и без изобретения костылей - это использовать memcpy. Подозреваю, что большинство компиляторов сумеют это дело соптимизировать и привести код к тому же состоянию, что и в "сложных" вариантах. Правда, так же как и в других предоставленных вариантах, код получится правильно работающим только на little-endian
1
зомбяк
1373 / 1044 / 302
Регистрация: 14.05.2017
Сообщений: 3,397
12.06.2017, 16:39 9
bugaboo, более правильным подходом был бы
C++
1
2
3
4
5
6
7
8
9
unsigned int uintof4b(char buffer[4])
{
    unsigned int x = 0;
    for (int i = 0; i < 4; i++)
    {
        x |= static_cast<unsigned int>(buffer[3 - i]) << (i * 8);
    }
    return x;
}
хотя не некоторых процессорах (i << 3) работает быстрее чем (i * 8).

Если использовать побитовое "или" вместо "+", то преобразование signed/unsigned теряет смысл. Правда так можно только для данного случая (собираемые байты друг с другом не пересекаются), иначе будет ошибка.

И по логике, если б небыло неяного преобразования из char в int, то в результате операции
C++
1
(unsigned char)buffer[3 - i] << (i << 3)
был бы 0 (при i > 0), т.к. в char всего один байт, и если его смещать, то не вошедшая в этот байт часть пропадёт.

Добавлено через 4 минуты
А стандартный вариант - это всё же использование memcpy -
C++
1
memcpy(&x, buffer, sizeof(int));
2
Evg
Эксперт CАвтор FAQ
21101 / 8118 / 628
Регистрация: 30.03.2009
Сообщений: 22,441
Записей в блоге: 30
12.06.2017, 16:49 10
Цитата Сообщение от TRam_ Посмотреть сообщение
хотя не некоторых процессорах (i << 3) работает быстрее чем (i * 8)
Я бы сказал, что не "на некоторых", а "скорее всего поголовно на всех"

Цитата Сообщение от TRam_ Посмотреть сообщение
Если использовать побитовое "или" вместо "+", то преобразование signed/unsigned теряет смысл
На коротком примере моделируются два случая: один с преобразованием в unsigned, другой без. Как видишь, разница есть. А потому преобразование в unsigned нельзя удалять независимо от того, через or делается сборка результата, или через plus

C
#include <stdio.h>
 
int main (void)
{
  unsigned int x;
  char buffer1 = 255;
 
  x = 0xaa000000;
  x |= (buffer1 << 8);
  printf ("%x\n", x);
 
  x = 0xaa000000;
  x |= ((unsigned char)buffer1 << 8);
  printf ("%x\n", x);
}
Код
$ gcc t.c
$ ./a.out
ffffff00
aa00ff00
1
зомбяк
1373 / 1044 / 302
Регистрация: 14.05.2017
Сообщений: 3,397
12.06.2017, 17:39 11
Evg, спасибо! Действительно неверно представлял себе поведение знаковых чисел при их преобразовании к типу с большим числом байтов. Так что или
C++
1
static_cast<unsigned char>(buffer[3 - i])
или
C++
1
(buffer[3 - i] & 0x000000FF)
0
-1 / 4 / 0
Регистрация: 12.06.2017
Сообщений: 60
12.06.2017, 20:21 12
Evg, я новичок и поэтому могу говорить только на уровне "у меня работает/не работает". Но хотелось бы, чтобы потом оно работало независимо от способа представления данных процессором. Суть у меня в том, что я читаю эти 4 charа из файла MIDI(функцией read), в котором всегда используется big-endian, и они из себя представляют беззнаковый int. Любой из этих байтов может запросто прочитаться как отрицательный (хотя в большинстве случаев таким не является, а является беззнаковым). Есть ли какой-то универсальный способ прочтения 4х байт в int из файла, чтобы результат преобразования был правильным, независимо от того, big-endian или little-endian схема используется в процессоре?
Я же не в космос улетаю, мне всего то надо 4 байта прочитать - откуда берутся такие сложности?
0
зомбяк
1373 / 1044 / 302
Регистрация: 14.05.2017
Сообщений: 3,397
12.06.2017, 21:33 13
bugaboo, сложность в том, что тут
1) идёт преобразование из одного байта в 4. То есть char был 1, а тут ещё три новых добавилось. Если использовать знаковый тип, то все биты новых байтов заполнятся 1цами в случае, если первый бит у него 1ца. Это в любом случае, что для big-endian, что для little-endian. Для большей производительности лучше сделать преобразование в unsigned типа указателя:
C++
1
unsigned char *uns_buffer = reinterpret_cast<unsigned char *>buffer;
2) порядок байтов, то есть, в одних архитектурах процессоров для счёта самыми старшими разрядами считаются первые байты (и далее последующие), а где-то наоборот. То есть в одном будет "0хFA6C9001", а в другом то же число - "0x01906CFA". Соответственно если в стандарте MIDI указан Big Endian, то чтоб производить арифметические операции с этим числом на процессорах x86, тебе нужно переворачивать байты, а если будешь писать например для архитектуры ARM, то переворачивать не нужно и достаточно простого memcpy()
1
Evg
Эксперт CАвтор FAQ
21101 / 8118 / 628
Регистрация: 30.03.2009
Сообщений: 22,441
Записей в блоге: 30
12.06.2017, 22:06 14
Цитата Сообщение от bugaboo Посмотреть сообщение
Есть ли какой-то универсальный способ прочтения 4х байт в int из файла, чтобы результат преобразования был правильным, независимо от того, big-endian или little-endian схема используется в процессоре?
В варианте с файлом есть как бы два endian'а: endian машины, на которой запущена программа и endian, в котором записаны данные в файле. Нужно просто взять и считать эти 4 байта в целочисленную переменную 4-байтного размера. В случае совпадения endian'ов машины и файла больше ничего делать не надо. Если endian'ы различаются, то байты в числе надо развернуть задом наперёд

Или, что тоже самое. Взять твой вариант из поста #7 и в зависимости от совпадающих или различающихся endian'ов прочитать байты в прямом или обратном порядке. Тут надо немного думать и экспериментировать, если честно, мне уже лениво под вечер

Какой endian у машины, на которой происходит запуск, можно проверить в runtime:

C
unsigned int x = 0x11223344;
char *p = (char*) &x;
if (*p == 0x44)
  little endian;
else
  big endian;
Добавлено через 8 минут
Цитата Сообщение от bugaboo Посмотреть сообщение
Любой из этих байтов может запросто прочитаться как отрицательный (хотя в большинстве случаев таким не является, а является беззнаковым)
К слову говоря, байт не бывает положительным или отрицательным. Байт - это всего лишь набор битов. А "положительный" и "отрицательный" - это всего лишь трактовки. Для самообразования можешь почитать:

Signed/Unsigned
Signed/Unsigned
Signed/Unsigned
Тип char.Signed/unsigned.Отличие типов данных.
1
-1 / 4 / 0
Регистрация: 12.06.2017
Сообщений: 60
14.06.2017, 02:13 15
Evg, тогда, наверно, такой вариант будет универсальным?
C++
1
2
3
4
5
6
        unsigned char buf[4];
        unsigned int x = 0;
        for (int i = 0; i < 4; i++)
            buf[i] = ifs.get();
        for (int i = 0; i < 4; i++)
            x += buf[3 - i] << (i << 3);
байты считываются заведомо как положительные числа в определенном порядке(файл заведомо big-endian, открыт как бинарный), а х вычисляется как сумма, то есть его представление в памяти не важно. У меня работает ))
0
зомбяк
1373 / 1044 / 302
Регистрация: 14.05.2017
Сообщений: 3,397
14.06.2017, 03:00 16
bugaboo, этот вариант будет работать только на процессорах с little-endian. Но, с другой стороны, полученную на данном компиляторе программу запустить на процессоре с big-endian не удастся - до тех пор пока её специально не скомпилируешь. Вот в этом случае и придётся вспоминать, что "у меня ж там был цикл, в котором надо будет поменять порядок". Но если кросс-платформенность не ожидается, то почему б и нет.
istream::get() возвращает int - http://www.cplusplus.com/reference/istream/istream/get/ - причём сам char там передаётся в беззнаковом виде, так что специально преобразовывать в unsigned char не потребуется (а вот в unsigned int надо). И цикл можно оптимизировать:

C++
1
2
3
        unsigned int x = 0;
        for (int i = 0; i < 4; i++)
            x += static_cast<unsigned int>(ifs.get()) << ((3 - i) << 3);
1
-1 / 4 / 0
Регистрация: 12.06.2017
Сообщений: 60
14.06.2017, 06:08 17
TRam_, большое спасибо, наконец-то получился красивый маленький универсальный код! С getом я действительно сплоховал...
Именно из=за кросс-платформенности я так и упарываюсь.
Последний вопрос - зачем нужен static cast? Почему не использовать приведение типа?
C++
1
2
3
unsigned int x = 0;     
for (__int8 i = 3; i >= 0; i--)
    x += (unsigned int)(ifs.get()) << (i << 3);
у меня работает )

Добавлено через 1 час 3 минуты
И даже вот так отлично работает:
C++
1
2
3
unsigned int x = 0;
for (__int8 i = 3; i >= 0; i--)
    x += (ifs.get()) << (i << 3);
то есть, происходит неявное приведение типа даже с "отрицательными" байтами
0
зомбяк
1373 / 1044 / 302
Регистрация: 14.05.2017
Сообщений: 3,397
14.06.2017, 06:44 18
Цитата Сообщение от bugaboo Посмотреть сообщение
Почему не использовать приведение типа?
Потому что это приведение типов по стандарту С, а по стандарту С++ приведение типов выполняется с помощью static/const/dynamic/reinterpret_cast.
Цитата Сообщение от bugaboo Посмотреть сообщение
C++
1
for (__int8 i = 3; i >= 0; i--)
от того, будешь ли использовать int8, или просто int, для 32-разрядного процессора будет почти одинаково. Ну а по поводу порядка (а потому отсутствующего вычитания
Цитата Сообщение от bugaboo Посмотреть сообщение
И даже вот так отлично работает:
) - да, так будет ещё оптимальнее.

Добавлено через 3 минуты
Цитата Сообщение от bugaboo Посмотреть сообщение
происходит неявное приведение типа
Я б не сказал. Signed/Unsigned - для сложения/вычитания знаковость/беззнаковость никак не влияет.
1
Эксперт С++
8067 / 3689 / 790
Регистрация: 15.11.2014
Сообщений: 8,376
14.06.2017, 07:11 19
Цитата Сообщение от Sergey-K Посмотреть сообщение
char ch[4] = {'a', 'b', 'c', 'd'};
int i = *(int *)ch;
Цитата Сообщение от George22 Посмотреть сообщение
Sergey-K красиво!
Код
warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
UB - такое UB.
1
-1 / 4 / 0
Регистрация: 12.06.2017
Сообщений: 60
14.06.2017, 07:34 20
Цитата Сообщение от TRam_ Посмотреть сообщение
Потому что это приведение типов по стандарту С, а по стандарту С++ приведение типов выполняется с помощью static/const/dynamic/reinterpret_cast.
а практическая разница какая-то есть?
Цитата Сообщение от TRam_ Посмотреть сообщение
для сложения/вычитания знаковость/беззнаковость никак не влияет.
тем более хорошо, результат то я получаю правильный )
Цитата Сообщение от TRam_ Посмотреть сообщение
от того, будешь ли использовать int8, или просто int, для 32-разрядного процессора будет почти одинаково
стараюсь не жрать лишнюю память... да и так удобнее ориентироваться
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
14.06.2017, 07:34

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Перевести биты int в unsigned int
Доброго времени суток, как можно получить из int -&gt; unsigned int, т.е. где все биты в таком же...

Vector<unsigned char> в int
есть vector&lt;unsigned char&gt; размером 4 байта..и мне надо перевести их в 1 число типа int. т.е. типо...

Перевести Int в unsigned char в формате hex
Приветствую всех. Что-то тупняки с утра дикие, помогите пожалуйста сообразить как правильно...

Как перевести сишный unsigned int в явский int?
Кто-нибудь занимался подобным переводом кода? Поначалу я думал, что разницы вообще нет, просто ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.