Подтвердить что ты не робот

Когда кастинг меняет биты значения в С++?

У меня есть С++ unsigned int, который фактически сохраняет подписанное значение. Я хочу передать эту переменную в signed int, так что значения без знака и знака имеют одинаковое двоичное значение.

unsigned int lUnsigned = 0x80000001;
int lSigned1 = (int)lUnsigned;                   // Does lSigned == 0x80000001?
int lSigned2 = static_cast<int>(lUnsigned);      // Does lSigned == 0x80000001?
int lSigned3 = reinterpret_cast<int>(lUnsigned); // Compiler didn't like this

Когда касты изменяют биты переменной в С++? Например, я знаю, что отбрасывание из int в float будет изменять биты, потому что int является двумя дополнениями и float является плавающей точкой. Но как насчет других сценариев? Я не понимаю правила для этого в С++.

В разделе 6.3.1.3 спецификации C99 говорится, что кастинг от неподписанного до знакового целого определяется с помощью компилятора!

4b9b3361

Ответ 1

Преобразование типа может

  • сохранить концептуальное значение (может потребоваться изменить битпаттер) или

  • сохранить битпаттер (возможно, потребуется изменить концептуальное значение).

Единственный С++ -актив, который всегда гарантирует битпаттер, - const_cast.

A reinterpret_cast, как следует из его названия, предназначен для сохранения битпаттерна и просто его интерпретации. Но стандарт позволяет реализовать очень много возможностей в реализации reinterpret_cast. В некотором случае a reinterpret_cast может изменить битпаттер.

A dynamic_cast обычно меняет как битпаттерн, так и значение, поскольку он обычно делится на объект и возвращает указатель/ссылку на под-объект запрошенного типа.

A static_cast может изменить битпаттер как для целых чисел, так и для указателей, но почти все существующие компьютеры используют представление целых чисел со знаком (называемое двумя дополнениями), где static_cast не изменит битпаттерн. Что касается указателей, достаточно сказать, что, например, когда базовый класс не является полиморфным, а производный класс является полиморфным, использование static_cast для перехода от указателя к производному к указателю на базу или наоборот может изменить битпаттерн (как вы можете видеть при сравнении указателей void*). Теперь целые числа...

С n битами значения целочисленный тип без знака имеет 2 ^ n значений в диапазоне от 0 до 2 ^ n-1 (включительно).

Стандарт С++ гарантирует, что любой результат типа завернут в этот диапазон путем добавления или вычитания подходящего кратного 2 ^ n.

Собственно, как описывает стандарт C; стандарт С++ просто говорит, что операции по модулю 2 ^ n, что означает то же самое.

С формой двух дополнений подписанное значение -x имеет тот же битпаттерн, что и беззнаковое значение -x + 2 ^ n. То есть тот же битпаттерн, что и стандарт С++, гарантирует, что вы получите преобразование -x в беззнаковый тип того же размера. То, что простые основы двух дополнений составляют, что это именно гарантия, которую вы ищете.: -)

И почти все существующие компьютеры используют две формы дополнения.

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

Ответ 2

Если вы отбрасываете меньший тип подписанного интеграла в более крупный подписанный тип интеграла, копии исходного наиболее значимого бита (1 в случае отрицательного числа) будут добавлены, если необходимо, чтобы сохранить целочисленное значение.

Если вы нанесете указатель на указатель одного из своих суперклассов, биты могут измениться, особенно если существует множественное наследование или виртуальные суперклассы.

Вы просите разницу между static_cast и reinterpret_cast.

Ответ 3

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

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

Если ваша реализация не использует 2 дополнения, то при нажатии между значениями, подписанными и без знака, будет изменен битовый шаблон, когда значение подписанного значения будет отрицательным. Однако такие реализации редки, но я не знаю, как использовать компиляторы не-2 в компиляторах С++.

Ответ 4

Использование C-style cast или static_cast для приведения unsigned int в signed int может все же позволить компилятору напрямую назначить первое последнему, как если бы актер не выполнялся, и, таким образом, может изменить бит, если значение unsigned int больше, чем может удерживать signed int. A reinterpret_cast должен работать, или вы можете набирать текст с помощью указателя:

unsigned int lUnsigned = 0x80000001; 
int lSigned1 = *((int*)&lUnsigned);
int lSigned2 = *(reinterpret_cast<int*>(&lUnsigned));

Ответ 5

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

Ответ 6

Вы ищете int lSigned = reinterpret_cast<int&>(lUnsigned);

Вы не хотите переинтерпретировать значение lUnsigned, вы хотите переинтерпретировать объект lUnsigned. Следовательно, приведение в ссылочный тип.

Ответ 7

Кастинг - это просто способ переопределить проверку типов, он не должен фактически изменять сами биты.