Неявные правила преобразования типов в операторах C++


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

int + float = ?
int * float = ?
float * int = ?
int / float = ?
float / int = ?
int / int = ?
int ^ float = ?

и так далее...

всегда ли выражение будет оцениваться как более точный тип? Отличаются ли правила для Java? Пожалуйста, поправьте меня, если я сформулировал этот вопрос неточно.

9 136

9 ответов:

в C++ операторы (для типов POD) всегда действуют на объекты одного типа.
Таким образом, если они не совпадают один будет повышен, чтобы соответствовать другой.
Тип результата операции совпадает с операндами (после преобразования).

If either is      long          double the other is promoted to      long          double
If either is                    double the other is promoted to                    double
If either is                    float  the other is promoted to                    float
If either is long long unsigned int    the other is promoted to long long unsigned int
If either is long long          int    the other is promoted to long long          int
If either is long      unsigned int    the other is promoted to long      unsigned int
If either is long               int    the other is promoted to long               int
If either is           unsigned int    the other is promoted to           unsigned int
If either is                    int    the other is promoted to                    int
Both operands are promoted to int

Примечание. Минимальный размер операций -int. Так что short/char звание int до завершения операции.

во всех ваших выражений int превращается в float перед операция выполнена. Результатом операции является float.

int + float =>  float + float = float
int * float =>  float * float = float
float * int =>  float * float = float
int / float =>  float / float = float
float / int =>  float / float = float
int / int                     = int
int ^ float =>  <compiler error>

арифметические операции с участием float результаты float.

int + float = float
int * float = float
float * int = float
int / float = float
float / int = float
int / int = int

для более подробного ответа. Посмотрите, что говорится в разделе §5/9 из стандарта C++

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

этот шаблон называется обычный арифметические преобразования, которые определяется следующим образом:

- Если один из операндов имеет тип long двойной, другой будет преобразован чтобы долго удваивать.

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

- в противном случае, если любой из операндов является float, другой должен быть преобразован в тип float.

- в противном случае Интеграл акциях (4.5) должны выполняться на обоих операнды.54)

- тогда, если любой из операндов без подписи долго другой должен быть преобразовано в unsigned long.

- В противном случае, если один операнд длинный int и другой неподписанный int, затем если длинный int может представлять все значения unsigned int, the беззнаковый инт должен быть преобразован в long int; в противном случае оба операнда преобразуется в unsigned long int.

- в противном случае, если один из операндов долго, другой будет быть преобразованы в длинный.

- в противном случае, если один из операндов без подписи, другой должен быть преобразован в unsigned.

[Примечание: В противном случае, единственный оставшийся случай что оба операнда имеют тип int ]

Так как другие ответы не говорят о правилах в C++11 Вот один. Из стандарта C++11 (проект n3337) §5/9:

этот шаблон называется обычные арифметические преобразования, которые определяются следующим образом:

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

- Если один из операндов имеет тип long двойной, другой должен быть преобразован в длинный двойной.

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

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

- в противном случае интегральные промоакции должны выполняться на обоих операндах. Затем к продвигаемым операндам применяются следующие правила:

- Если оба операнда имеют одинаковый тип, нет необходима дальнейшая конверсия.

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

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

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

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

посмотреть здесь список, который часто обновляется.

этот ответ направлен в значительной степени на комментарий, сделанный @RafałDowgird:

" минимальный размер операций-int."- Это было бы очень странно (как насчет архитектур, которые эффективно поддерживают char / short операции?) Это действительно в спецификации C++?

имейте в виду, что стандарт C++ имеет очень важное правило "как-если". См. раздел 1.8: выполнение программы:

3) это положение иногда называется правилом "как-будто", потому что реализация может игнорировать любые требования Стандарта пока результат, как если бы требование было исполнено, насколько как можно определить из наблюдаемого поведения программы.

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

следовательно, в случае теоретического компьютера с супер-быстрые 8-битные операции, неявное продвижение до int для арифметики может иметь значение. Однако для многих операций вы не можете сказать, действительно ли компилятор выполнял операции с точностью int а затем преобразуется в char для хранения в переменной, или если операции были выполнены в char все время.

рассмотрим, например,unsigned char = unsigned char + unsigned char + unsigned char, где добавление будет переполняться (предположим, что значение 200 для каждого). Если вы продвинулись до int, вы получите 600, который затем будет неявно вниз брошен в unsigned char, что бы обернуть по модулю 256, тем самым давая окончательный результат 88. Если бы вы не делали таких рекламных акций,вам пришлось бы обернуть между первыми двумя дополнениями, что уменьшило бы проблему с 200 + 200 + 200 до 144 + 200, что составляет 344, что сокращается до 88. Другими словами, программа не знает разницы, поэтому компилятор может игнорировать мандат на выполнение промежуточных операций в int Если операнды имеют более низкий ранг, чем int.

это верно в общем сложения, вычитания и умножения. Это не верно в целом для деления или модуля.

Если вы исключаете беззнаковые типы, есть упорядоченный иерархия: подпись чар, короткий, интервал, долго, долго, долго, поплавок, двойной, двойной. Первое, что приходит перед инт в выше будет преобразован в int. Затем, в двоичной операции, более низкий ранговый тип будет преобразован в более высокий, и результаты будут типа выше. (Вы заметите, что от иерархия, в любое время плавающей точкой и целочисленным типом являются включенный, интегральный тип будет преобразован к плавающий тип точки.)

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

мой решение до Преобразование

  • либо операнд имеет тип двойной. --- >Другой операнд преобразуется в тип двойной.

  • предыдущее условие не выполнено, и любой операнд имеет тип двойной. --- >Другой операнд преобразуется в тип двойной.

  • предыдущие условия не выполнены, и любой операнд имеет тип float. --- >Другой операнд преобразуется в тип float.

  • предыдущие условия не выполнены (ни один из операндов не имеет плавающих типов). --- >Интегральные акции выполняются на операндах следующим образом:

    • если любой из операндов имеет тип unsigned long, другой операнд преобразуется в тип unsigned long.
    • если предыдущее условие не выполнено, и если любой из операндов имеет тип долго и другие типа unsigned int, оба операнда преобразуются в тип unsigned long.
    • если два предыдущих условия не выполняются, и если любой из операндов имеет тип долго, t он другой операнд преобразуется в тип долго.
    • Если предыдущие три условия не будут выполнены, и если любой из операндов имеет тип unsigned int, другой операнд преобразуется в тип неподписанных int.
    • если ни одно из предыдущих условий, то оба операнда преобразуются в тип int.

2 . правила преобразования целого числа

  • Целое Число Акций:

целочисленные типы, меньшие, чем int, продвигаются при выполнении операции над ними. Если все значения первого типа могут быть представлены как int, значение меньше тип преобразуется в int; в противном случае он преобразуется в unsigned int. Целочисленные продвижения применяются как часть обычных арифметических преобразований к определенным выражениям аргумента; операндам унарных операторов +, -, и~; и операндам операторов сдвига.

  • Ранг Преобразования Целых Чисел:

    • никакие два целочисленных типа со знаком не должны иметь одинаковый ранг, даже если они имеют одинаковое представление.
    • ранг целого числа со знаком тип должен быть больше ранга любого целочисленного типа со знаком с меньшей точностью.
    • в звании long long int должна быть больше, чем ранг long int, который должен быть больше, чем ранг int, который должен быть больше, чем ранг short int, который должен быть больше, чем ранг signed char.
    • ранг любого целочисленного типа без знака должен равняться рангу соответствующего целочисленного типа со знаком, если таковой имеется.
    • ранг любого стандартного целого числа тип должен быть больше ранга любого расширенного целочисленного типа с такой же шириной.
    • в звании char равняется рангу signed char и unsigned char.
    • ранг любого расширенного целочисленного типа со знаком относительно другого расширенного целочисленного типа со знаком с той же точностью определяется реализацией, но все же подчиняется другим правилам определения ранга преобразования целых чисел.
    • для всех целочисленных типов T1, T2 и T3, если T1 имеет больший ранг чем T2 и T2 имеет больший ранг, чем T3, то T1 имеет больший ранг, чем T3.
  • Обычные Арифметические Преобразования:

    • если оба операнда имеют один и тот же тип, дальнейшее преобразование не требуется.
    • если оба операнда имеют один и тот же целочисленный тип (со знаком или без знака), то операнд с типом меньшего целочисленного ранга преобразования преобразуется в тип операнда с большим рангом.
    • если операнд, который имеет беззнаковый целочисленный тип имеет ранг, больший или равный рангу типа другого операнда, операнд со знаком целочисленного типа преобразуется в тип операнда с беззнаковым целочисленным типом.
    • если тип операнда со знаком целочисленного типа может представлять все значения типа операнда со знаком целочисленного типа, то операнд со знаком целочисленного типа преобразуется в тип операнда со знаком целочисленного типа.
    • в противном случае, оба операнда преобразуются в беззнаковый целочисленный тип, соответствующий типу операнда со знаком целочисленного типа. Определенные операции могут добавлять или изменять семантику обычных арифметических операций.

вся Глава 4 говорит о преобразованиях, но я думаю, что вы должны быть в основном заинтересованы в них:

4.5 интегральный акции [конв.пром]
Собой rvalue типа char, чар, подписанные, неподписанные символ, короткое int или unsigned короткие int может быть преобразован в rvalue типа int, если int может представлять все значения исходного типа; другое -
мудрый, исходный rvalue может быть преобразован в rvalue типа unsigned int.
Собой rvalue типа wchar_t (3.9.1) или тип перечисления (7.2) может быть преобразован в rvalue первого
из следующих типов, которые могут представлять все значения его базового типа: int, unsigned int,
долго, или без подписи долго.
Значение rvalue для интегрального битового поля (9.6) может быть преобразовано в значение rvalue типа int, если int может представлять все
значения битового поля; в противном случае он может быть преобразован в unsigned int, если unsigned int может rep-
возмущает все значения битового поля. Если битовое поле еще больше, к нему не применяется интегральное продвижение. Если
бит-поле имеет перечислимый тип,оно рассматривается как любое другое значение этого типа для целей продвижения.
Значение типа bool может быть преобразовано в значение типа int, при этом false становится нулем, а true
стать одним из них.
Эти конверсии называются интегральными акциями.

4.6 продвижение с плавающей запятой [конв.fpprom]
Значение типа float может быть преобразовано в значение типа double. Значение не изменяется.
Это преобразование называется продвижением с плавающей запятой.

поэтому все преобразования с использованием float-результат float.

только один с участием обоих int-результат int : int / int = int

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

в выражениях, в которых участвуют действительное число и целое число, целое число будет повышено до действительного числа. Например, в int + float типом выражения является float.

другой разница связана с возможностями типа. Например, выражение, включающее int и long int, приведет к типу long int.

будьте осторожны!

преобразования происходят слева направо.

попробуйте это:

int i = 3, j = 2;
double k = 33;
cout << k * j / i << endl; // prints 22
cout << j / i * k << endl; // prints 0