Является ли Sign Extension в C ++ опцией компилятора или зависит от компилятора или цели?

Следующий код был скомпилирован на 3 разных компиляторах и 3 разных процессорах и дал 2 разных результата:

typedef unsigned long int u32;
typedef signed long long s64;
int main ()
{ u32 Operand1,Operand2;
s64 Result;
Operand1=95;
Operand2=100;
Result= (s64)(Operand1-Operand2);}

Результат дает 2 результата:
или
-5 или же 4294967291

Я понимаю, что операция (Operand1-Operand2) выполняется как 32-разрядное вычисление без знака, затем при приведении к s64 расширение знака было сделано правильно в первом случае, но не было сделано правильно для второго случая.

Мой вопрос заключается в том, можно ли управлять расширением знака с помощью параметров компилятора, или оно зависит от компилятора, или, возможно, оно зависит от цели.

-3

Решение

Ваша проблема в том, что вы предполагаете unsigned long int иметь ширину 32 бита и signed long long быть 64-битной шириной. Это предположение неверно.

Мы можем визуализировать, что происходит используя типы с гарантированной (по стандарту) шириной в битах:

int main() {
{
uint32_t large = 100, small = 95;
int64_t result = (small - large);
std::cout << "32 and 64 bits: " << result << std::endl;
}  // 4294967291
{
uint32_t large = 100, small = 95;
int32_t result = (small - large);
std::cout << "32 and 32 bits: " << result << std::endl;
}  // -5
{
uint64_t large = 100, small = 95;
int64_t result = (small - large);
std::cout << "64 and 64 bits: " << result << std::endl;
}  // -5
return 0;
}

В каждом из этих трех случаев выражение small - large приводит в результате неподписанный целочисленный тип (соответствующей ширины). Этот результат рассчитывается с использованием модульной арифметики.

В первом случае, поскольку этот неподписанный результат может быть сохранен в более широком целом числе со знаком, преобразование значения не выполняется.

В остальных случаях результат не могу храниться в подписанном целом числе. Таким образом, выполняется преобразование, определяемое реализацией, что обычно означает интерпретацию битовой комбинации беззнакового значения как знакового значения. Поскольку результат «большой», будут установлены старшие биты, которые при обработке как знаковое значение (в дополнение к двум) эквивалентны «маленькому» отрицательному значению.


Чтобы выделить комментарий от Lưu Vĩnh Phúc:

Operand1-Operand2 поэтому без знака, при приведении к s64 это всегда нулевое расширение. [..]

Расширение знака выполняется только в первом случае, так как только тогда происходит расширяющее преобразование, и оно действительно всегда является нулевым расширением.


Цитаты из стандарт, Акцент мой. относительно small - large:

Если тип назначения является беззнаковым, полученное значение является наименьшим целым числом без знака, соответствующим исходному целому числу (по модулю 2^n$ где n — количество битов, используемых для представления типа без знака). [..]

§ 4.7 / 2

Что касается преобразования из неподписанного в подписанное:

Если тип назначения [целочисленного преобразования] подписан, значение не изменяется, если оно может быть представлено в типе назначения; в противном случае значение от реализации.

§ 4.7 / 3

5

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

Расширение знака зависит от платформы, где платформа представляет собой сочетание компилятора, целевой аппаратной архитектуры и операционной системы.

Более того, как отметил Пол Р, ширина встроенных типов (например, unsigned long) также зависит от платформы. Используйте типы из <cstdint> чтобы получить типы фиксированной ширины. Тем не менее, они являются просто зависимыми от платформы определениями, поэтому их поведение расширения знака все еще зависит от платформы.

Вот хороший почти дублирующий вопрос о размерах шрифта. А также Вот хорошая таблица об отношениях размера шрифта.

2

Типы продвижения и соответствующие расширения знака определяются языком C ++.

Что не указано, но зависит от платформы, так это диапазон предоставляемых целочисленных типов. Это даже соответствует стандартам char, short int, int, long int а также long long int иметь одинаковый диапазон при условии, что этот диапазон удовлетворяет требованиям стандарта C ++ для long long int, На такой платформе расширения или сужения не будет, но подписано<-> беззнаковое преобразование все еще может изменить значения.

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector