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

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

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

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

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

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 double, другой должен быть преобразован в long double.

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

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

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

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

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

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

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

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

Поскольку другие ответы не говорят о правилах в C++11, вот один. Из стандарта C++11 (черновик №3337) §5/9:

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

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

- Если один из операндов имеет тип long double, другой должен быть преобразован в 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,

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

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

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

Мое решение проблемы получило WA(неправильный ответ), затем я изменил один из int в long long int и это дало AC(принять). Раньше я пытался сделать long long int += int * intи после того, как я исправлю это long long int += long long int * int, Погуглил я придумал,

1. Арифметические преобразования

Условия для преобразования типов:

Условия встретились ---> Конверсия

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

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

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

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

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

2 Целочисленные правила преобразования

  • Целочисленные Акции:

Целочисленные типы, меньшие чем int, повышаются, когда над ними выполняется операция. Если все значения исходного типа могут быть представлены как int, значение меньшего типа преобразуется в 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.
  • Обычные арифметические преобразования:

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

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

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

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

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

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

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

Поэтому все преобразования, включающие float - результат float.

Только тот, который включает оба int - результатом является int: int / int = int

Предостережение!

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

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

int i = 3, j = 2;
double k = 33;
cout << k * j / i << endl; // prints 22
cout << j / i * k << endl; // prints 0
Другие вопросы по тегам