Я новичок в C++
программирование. Я пытаюсь реализовать код, с помощью которого я могу сделать одно целое значение из 6
или больше individual bytes
,
Я реализовал то же самое для 4 bytes
и это работает
Мой код на 4 байта:
char *command = "\x42\xa0\x82\xa1\x21\x22";
__int64 value;
value = (__int64)(((unsigned char)command[2] << 24) + ((unsigned char)command[3] << 16) + ((unsigned char)command[4] << 8) + (unsigned char)command[5]);
printf("%x %x %x %x %x",command[2], command[3], command[4], command[5], value);
Используя этот код, значение value
является 82a12122
но когда я пытаюсь сделать для 6 байт, то результат был неправильным.
Код для 6 байтов:
char *command = "\x42\xa0\x82\xa1\x21\x22";
__int64 value;
value = (__int64)(((unsigned char)command[0] << 40) + ((unsigned char)command[1] << 32) + ((unsigned char)command[2] << 24) + ((unsigned char)command[3] << 16) + ((unsigned char)command[4] << 8) + (unsigned char)command[5]);
printf("%x %x %x %x %x %x %x", command[0], command[1], command[2], command[3], command[4], command[5], value);
Выходное значение value
является 82a163c2
что неправильно, мне нужно 42a082a12122
,
Так может кто-нибудь сказать мне, как получить ожидаемый результат и что не так с 6 Byte
Код.
Заранее спасибо.
Просто приведите каждый байт к достаточно большому типу без знака перед сдвигом. Даже после целого промоушена unsigned int
), тип недостаточно велик, чтобы смещаться более чем на 32 байта (в обычном случае, который, кажется, вам подходит).
Смотрите здесь для демонстрации: https://godbolt.org/g/x855XH
unsigned long long large_ok(char x)
{
return ((unsigned long long)x) << 63;
}
unsigned long long large_incorrect(char x)
{
return ((unsigned long long)x) << 64;
}unsigned long long still_ok(char x)
{
return ((unsigned char)x) << 31;
}
unsigned long long incorrect(char x)
{
return ((unsigned char)x) << 32;
}
Проще говоря:
Операторы сдвига продвигают свои операнды int
/unsigned int
автоматически. Вот почему ваша четырехбайтовая версия работает: unsigned int
достаточно велик для всех ваших смен. Однако (в вашей реализации, как и в большинстве распространенных) он может содержать только 32 бита, и компилятор не будет автоматически выбирать 64-битный тип, если вы переключаетесь более чем на 32 бита (что было бы невозможно знать компилятору) ,
Если вы используете достаточно большие целочисленные типы для операндов сдвига, в результате сдвиг будет иметь больший тип, и сдвиги будут делать то, что вы ожидаете.
Если вы включите предупреждения, ваш компилятор, вероятно, также будет жаловаться вам на то, что вы сдвигаетесь на большее количество бит, чем имеет тип, и, следовательно, всегда получаете ноль (см. Демонстрацию).
(Упомянутое количество битов, конечно, определяется реализацией.)
Последнее замечание: типы начинаются с двойного подчеркивания (__
) или подчеркивание + заглавная буква зарезервированы для реализации — использование их технически не «безопасно». Современный C ++ предоставляет вам такие типы, как uint64_t
это должно иметь указанное количество битов — используйте их вместо.
Ваш сдвиг переполняет байты, и вы неправильно печатаете целые числа.
Этот код работает:
(Принять к сведению формат печати и как изменения сделаны в uint64_t
)
#include <stdio.h>
#include <cstdint>
int main()
{
const unsigned char *command = (const unsigned char *)"\x42\xa0\x82\xa1\x21\x22";
uint64_t value=0;
for (int i=0; i<6; i++)
{
value <<= 8;
value += command[i];
}
printf("%x %x %x %x %x %x %llx",
command[0], command[1], command[2], command[3], command[4], command[5], value);
}