Неявные правила преобразования типов в операторах C ++ - PullRequest
150 голосов
/ 06 апреля 2011

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

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

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

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

Ответы [ 9 ]

197 голосов
/ 06 апреля 2011

В 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>
30 голосов
/ 06 апреля 2011

Арифметические операции с участием float приводят к float.

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

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

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

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

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

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

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

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

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

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

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

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

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

16 голосов
/ 26 мая 2014

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

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

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

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

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

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

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

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

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

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

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

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

5 голосов
/ 20 января 2012

Этот ответ в значительной степени направлен на комментарий, сделанный @ 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.

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

3 голосов
/ 06 апреля 2011

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

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

2 голосов
/ 15 июня 2014

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

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

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

Условия выполнения ---> Преобразование

  • Любой операнд имеет тип длинный двойной .---> Другой операнд преобразуется в тип 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.
  • Обычные арифметические преобразования:

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

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

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

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

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

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

1 голос
/ 06 апреля 2011

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

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

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

0 голосов
/ 04 августа 2014

Протест!

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

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

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