Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
prosto_lynx
49 / 24 / 1
Регистрация: 09.06.2008
Сообщений: 226
#1

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

06.04.2012, 21:33. Просмотров 2945. Ответов 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
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
06.04.2012, 21:33
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Как массив char[4] перевести в unsigned int? (C++):

Надо перевести переменную типа unsigned char* в signed int и обратно - C++
у меня есть переменная типа unsigned char*, мне нужно перевести ее в signed int , провести арифметические вычисления и затем перевести ее...

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

Vector<unsigned char> в int - C++
есть vector&lt;unsigned char&gt; размером 4 байта..и мне надо перевести их в 1 число типа int. т.е. типо int command = tempN.data(); но ...

Как перевести из char в int? - C++
нужно присвоить значение массива char A в int B, например B=A, но выбивает ошибку, пробовал B=atoi(&amp;A); но выбивает другое число

Как исправить ошибку невозможно преобразовать аргумент 1 из "unsigned int" в "unsigned int []"? - C++
Ребят, срочно прошу вас помочь.. Есть ошибка (невозможно преобразовать аргумент 1 из &quot;unsigned int&quot; в &quot;unsigned int &quot;) как ее...

Размер для данных (int, char, long, double, short, unsigned, float) - C++
Напишите программу, которая будет определять размер для данных (int, char, long, double, short, unsigned, float) и выводить информацию (о...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Sergey-K
233 / 224 / 13
Регистрация: 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
George22
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
17819 / 6029 / 388
Регистрация: 30.03.2009
Сообщений: 16,559
Записей в блоге: 26
07.04.2012, 12:56 #4
При этом надо понимать, что код из поста 2 и код с union'ом из поста 3 будут работать только на little-endian машинах. Код из поста 2 надёжно будет работать только на машинах, в которых разрешены невыровненные обращения в память. Intel'овские процессоры удовлетворяют обоим критериям, а потому для "домашнего" использования или для программы, которая будет работать исключительно на Intel'е это канает, но в общем случае - нет
2
prosto_lynx
49 / 24 / 1
Регистрация: 09.06.2008
Сообщений: 226
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
17819 / 6029 / 388
Регистрация: 30.03.2009
Сообщений: 16,559
Записей в блоге: 26
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
bugaboo
-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
17819 / 6029 / 388
Регистрация: 30.03.2009
Сообщений: 16,559
Записей в блоге: 26
12.06.2017, 16:19 #8
Цитата Сообщение от bugaboo Посмотреть сообщение
Странно, что для такой простой задачи приходится изобретать такой сложный костыль
Просто и без изобретения костылей - это использовать memcpy. Подозреваю, что большинство компиляторов сумеют это дело соптимизировать и привести код к тому же состоянию, что и в "сложных" вариантах. Правда, так же как и в других предоставленных вариантах, код получится правильно работающим только на little-endian
1
TRam_
224 / 231 / 58
Регистрация: 14.05.2017
Сообщений: 817
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
17819 / 6029 / 388
Регистрация: 30.03.2009
Сообщений: 16,559
Записей в блоге: 26
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
TRam_
224 / 231 / 58
Регистрация: 14.05.2017
Сообщений: 817
12.06.2017, 17:39 #11
Evg, спасибо! Действительно неверно представлял себе поведение знаковых чисел при их преобразовании к типу с большим числом байтов. Так что или
C++
1
static_cast<unsigned char>(buffer[3 - i])
или
C++
1
(buffer[3 - i] & 0x000000FF)
0
bugaboo
-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
TRam_
224 / 231 / 58
Регистрация: 14.05.2017
Сообщений: 817
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
17819 / 6029 / 388
Регистрация: 30.03.2009
Сообщений: 16,559
Записей в блоге: 26
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
bugaboo
-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
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.06.2017, 02:13
Привет! Вот еще темы с ответами:

Как правильно перевести int и string в *char для записи в SQLlite? - C++
Доброго времени суток! Вопрос такой: Каким образом обычно переводятся значения типа int и string в SQL-запрос типа *char ? Вот...

Доступны ли побитовые операции с unsigned char типом (одно-байтовой переменной) без неявного приведения к INT - C++
Отказавшись от bitset мне удалось ускорить работу программы примерно в 2,25 раза Вот её код (ребят cyberforum.ru - не сохраняет оригинал...

Перевести строку типа char в массив типа int - C++
Задание : В текстовом файле INPUT.TXT записаны целые числа через пробел, возможно, в несколько строк. За один просмотр файла сформировать...

Как перевести массив char[] в char* - C++
Не знаю как перевести массив char в переменную char*


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
14.06.2017, 02:13
Ответ Создать тему
Опции темы

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