Как превратить целочисленное значение со знаком в беззнаковое, в соответствии с его битами?
Я хочу превратить подписанное значение в неподписанное (например, int8_t
в uint8_t
), но также он должен держать свои биты.
Как мне это сделать?
3 ответа
На практике: вы можете просто присвоить подписанное значение uint8_t
,
u = i;
или вы можете инициализировать его со значением со знаком,
uint8_t u = i;
Предполагается, что целочисленное представление со знаком в виде двух дополнений, которое сегодня используется повсеместно. При таком представлении биты сохраняются точно. Квалификация "на практике" относится к этому допущению.
Например, на современном компьютере 8-битное представление со знаком, например, -42, является числом битового шаблона -42 + 256, которое является (битовым шаблоном) 214. Преобразование этого в беззнаковый гарантируется стандартом для получения того же значения по модулю 256 И так это тот же битпаттерн, а именно битпаттерн 214.
Переход от подписи к неподписанию хорошо определен стандартом, хотя сохранение битовой комбинации (1) обычно является практическим эффектом (все современные компьютеры спроектированы таким образом). Однако, идя в противоположном направлении, вы сталкиваетесь с конкретными для компилятора эффектами, если значение без знака не может быть представлено. Требуется больше внимания для этого преобразования, потому что это вопрос усмотрения компилятора, а не практическая гарантия на аппаратном уровне.
(1) Как MM объясняет в своем ответе конкретный тип со знаком в вашем примере, int8_t
является тем, что, поскольку C11 было гарантировано два дополнения в C. Я не вижу этот язык в окончательном проекте стандарта C99, поэтому, вероятно, его не было в C99, и, следовательно, нет ни в C++11, ни в C +. +14, которые основаны на C99, но, вероятно, есть в C++17, который, я считаю, основан на C11.
С intN_t
типы вы можете просто написать:
int8_t i = something;
uint8_t u = i;
потому что эти типы должны использовать представление дополнения 2, где это преобразование определено для сохранения битов.
Ссылка: C++14 [cstdint.syn]/2:
Заголовок определяет все функции, типы и макросы так же, как 7.18 в стандарте C.
И C11 7.20.1.1/1 (C99 7.18.1.1):
Имя определения типа
intN_t
обозначает целочисленный тип со знаком с ширинойN
, нет дополнительных битов, и представление дополнения до двух.
Чтобы сохранить представление для других целочисленных типов, используйте:
int i = something;
unsigned int i = *(unsigned int *)&i;
Вы можете сделать это с любой парой соответствующих типов со знаком и без знака. Это безопасно, за исключением возможности генерирования представления ловушки.
Попробуйте с явным преобразованием типов. Преобразование (небезопасного) типа с использованием static_cast необходимо для получения "необработанных байтов" переменной. Чтобы преобразовать значение в данный тип, вы пишете следующее:
static_cast<type_to_convert_to>(expression)
С static_cast приведение проверяется статически во время компиляции.
#include <iostream>
int main() {
int8_t i {11};
uint8_t i2 = static_cast<uint8_t>(i);
std::cout << "i occupies " << sizeof(i) << " bytes." << std::endl;
std::cout << "i2 occupies " << sizeof(i2) << " bytes." << std::endl;
}