У меня есть следующая функция:
void func(unsigned long v)
{
char max_byte = 0xFF;
char buffer[8];
buffer[0] = static_cast<char>((v) & max_byte);
buffer[1] = static_cast<char>((v >> 8) & max_byte);
buffer[2] = static_cast<char>((v >> 16) & max_byte);
buffer[3] = static_cast<char>((v >> 24) & max_byte);
buffer[4] = static_cast<char>((v >> 32) & max_byte);
buffer[5] = static_cast<char>((v >> 40) & max_byte);
buffer[6] = static_cast<char>((v >> 48) & max_byte);
buffer[7] = static_cast<char>((v >> 56) & max_byte);
}
который занимает unsigned long
аргумент и вставьте его 8 байтов char
буфер (не пытайтесь выяснить, почему. Это краткая версия значимой функции).
Этот код хорошо компилируется на 64-битной, но на 32-битной я получаю следующее предупреждение:
warning: right shift count >= width of type
ссылаясь на строки:
buffer[4] = static_cast<char>((v >> 32) & max_byte);
buffer[5] = static_cast<char>((v >> 40) & max_byte);
buffer[6] = static_cast<char>((v >> 48) & max_byte);
buffer[7] = static_cast<char>((v >> 56) & max_byte);
Я думаю, что понимаю предупреждение, но я не уверен, что мне следует делать, чтобы иметь возможность плавно скомпилировать его и на 32-битной системе.
unsigned long
гарантированно имеет только 32 бита. Увидеть Вот. Вам нужно использовать unsigned long long
иметь гарантированные 64 бита.
Еще лучше было бы использовать целое число фиксированной ширины, то есть uint64_t
, Они определены в заголовке <cstdint>
(или же <stdint.h>
).
Использовать целочисленные типы фиксированной ширины. В этом случае вы хотите std::uint64_t
,
При написании кода, который зависит от целочисленного размера, вам действительно нужно использовать <stdint.h>
,
#include <stdint.h>
void func(uint64_t v)
{
static const uint8_t max_byte = 0xFF; // Let the compiler hardcode this constant.
uint8_t buffer[8];
buffer[0] = static_cast<uint8_t>((v) & max_byte);
buffer[1] = static_cast<uint8_t>((v >> 8) & max_byte);
buffer[2] = static_cast<uint8_t>((v >> 16) & max_byte);
buffer[3] = static_cast<uint8_t>((v >> 24) & max_byte);
buffer[4] = static_cast<uint8_t>((v >> 32) & max_byte);
buffer[5] = static_cast<uint8_t>((v >> 40) & max_byte);
buffer[6] = static_cast<uint8_t>((v >> 48) & max_byte);
buffer[7] = static_cast<uint8_t>((v >> 56) & max_byte);
}
Возможно, я ошибаюсь, если предположить, что ни один из ответов на самом деле не доходит до сути этого вопроса, поэтому здесь идет речь.
Компиляция в виде 64-битного двоичного файла long определяется как 64-битное значение (или 8 байтов), тогда как 32-битный двоичный код long совпадает с int, который составляет 32 бита или 4 байта.
Есть несколько решений проблемы:
1. переопределите параметр на long long или int64, как предлагается в других ответах.
2. добавить определение препроцессора, чтобы заблокировать ошибочные битовые операции. Такие как…
#ifdef __LP64__
buffer[4] = static_cast<uint8_t>((v >> 32) & max_byte);
buffer[5] = static_cast<uint8_t>((v >> 40) & max_byte);
buffer[6] = static_cast<uint8_t>((v >> 48) & max_byte);
buffer[7] = static_cast<uint8_t>((v >> 56) & max_byte);
#endif
Это гарантирует, что long обрабатывается в соответствии с архитектурой процессора и не заставляет long всегда быть 64-битным.
3. Использование объединения приведет к тому же конечному результату для предоставленного кода
void func(unsigned long v)
{
union {
unsigned long long ival;
unsigned char cval[8];
} a;
a.ival = v;
}
конечно, если вы используете c ++, вы можете сохранить любой базовый тип данных аналогичным образом, изменив вышеприведенное описание следующим образом:
template<class I>
void func(I v) {
union {
unsigned long long ival;
unsigned char cval[8];
I val;
} a;
a.val = v;
}