Как превратить целочисленное значение со знаком в беззнаковое, в соответствии с его битами?

Я хочу превратить подписанное значение в неподписанное (например, 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;


}
Другие вопросы по тегам