как взять два дополнения байта в переполнении стека

Я смотрю на некоторый код C ++, и я вижу:

 byte b = someByteValue;
// take twos complement
byte TwosComplement = -b;

Этот код принимает двойное дополнение b? Если нет, что он делает?

5

Решение

это код определенно вычисляет двойное дополнение 8-битного двоичного числа в любой реализации, где stdint.h определяет uint8_t:

#include <stdint.h>
uint8_t twos_complement(uint8_t val)
{
return -(unsigned int)val;
}

Это потому, если uint8_t доступно, это должен быть тип без знака, который имеет ширину ровно 8 бит. Преобразование в unsigned int необходимо, потому что uint8_t определенно уже int, Без преобразования значение будет повышено до int до того, как он будет отменен, поэтому, если вы работаете на машине, не являющейся дополнением к двойкам, она не будет принимать дополнения к двум.

В более общем смысле этот код вычисляет двойное дополнение значения с любой тип без знака (с использованием конструкций C ++ для иллюстрации — поведение унарного минуса одинаково в обоих языках, при условии отсутствия пользовательских перегрузок):

#include <cstdint>
#include <type_traits>

template <typename T>
T twos_complement(T val,
// "allow this template to be instantiated only for unsigned types"typename std::enable_if<std::is_unsigned<T>::value>::type* = 0)
{
return -std::uintmax_t(val);
}

потому что унарный минус определен так, чтобы принимать двойное дополнение применительно к неподписанным типам. Нам все еще нужен приведение к типу без знака, который не является более узким, чем int, но теперь нам нужно, чтобы он был как минимум настолько широким, насколько это возможно Tотсюда uintmax_t,

Тем не менее, унарный минус делает не обязательно вычислить двойное дополнение значения, тип которого подписанный, потому что C (и C ++) все еще явно разрешают реализации, основанные на процессорах, которые не используйте два дополнения для подписанных количеств. Насколько я знаю, ни один такой процессор не производился по крайней мере в течение 20 лет, поэтому постоянное обеспечение для них довольно глупо, но это так. Если вы хотите вычислить двойное дополнение значения, даже если его тип подписан, вы должны сделать это: (снова C ++)

#include <type_traits>

template <typename T>
T twos_complement(T val)
{
typedef std::make_unsigned<T>::type U;

return T(-uintmax_t(U(val)));
}

то есть преобразовать в соответствующий тип без знака, затем в uintmax_t, затем примените унарный минус, затем выполните обратное преобразование в возможно подписанный тип. (Приведение к U требуется, чтобы убедиться, что значение равно нулю, а не расширено от его естественной ширины.)

(Однако, если вы обнаружите, что делаете это, остановите и вместо этого поменяйте типы на unsigned. Ваша будущая личность поблагодарит вас.)

10

Другие решения

Правильное выражение будет выглядеть

byte TwosComplement = ~b + 1;

Примечание: при условии, что байт i определен как unsigned char

5

На машине дополнения до двух отрицание вычисляет дополнение до двух, да.

На Unisys что-то, что-то, возможно, теперь мертвое и похороненное (но все еще существующее несколько лет назад), нет для подписанного типа.

C и C ++ поддерживают два дополнения, одно дополнение и представление знака и величины целых чисел со знаком, и только с дополнением два отрицание делает дополнение двух.


С byte как отрицание типа без знака плюс преобразование в byte генерирует битовый шаблон дополнения до двух, независимо от целочисленного представления, потому что преобразование в арифметику без знака и без знака происходит по модулю 2N где N количество бит представления значения

Таким образом, результирующее значение после присвоения или инициализации с -x равно 2N — х, который является дополнением к двум х.

Это не означает, что само отрицание обязательно вычисляет битовый шаблон дополнения двух. Чтобы понять это, обратите внимание, что с byte определяется как unsigned char, и с sizeof(int) > 1, byte значение повышается до int перед отрицанием, то есть операция отрицания выполняется со знаком типа. Но преобразование полученного отрицательного значения в беззнаковый байт создает двоичный набор дополнений по определению и гарантию C ++ по модулю арифметики и преобразованию в беззнаковый тип.


Полезность формы дополнения 2 следует из 2N — х = 1 + ((2N — 1) — x), где последняя круглая скобка представляет собой единичный битпаттерн минус Икс, т.е. простая побитовая инверсия x,

2
По вопросам рекламы [email protected]