Продвижение по плавающей запятой: стростюп против компилятора - кто прав?
В разделе 10.5.1 новой статьи Stroustrup "Язык программирования С++ - четвертое издание" он говорит, что перед выполнением арифметической операции интегральное продвижение используется для создания ints из более коротких целочисленных типов, и аналогичным образом, точечное продвижение используется для создания двойников из поплавков.
Я подтвердил первое требование со следующим кодом:
#include <iostream>
#include <typeinfo>
int main()
{
short a;
short b;
std::cout << typeid(a + b).name() << std::endl;
}
Это выводит "int" с vС++ и "i" с gcc.
Но тестируя его с помощью float вместо коротких замыканий, выход по-прежнему остается "float" или "f":
#include <iostream>
#include <typeinfo>
int main()
{
float a;
float b;
std::cout << typeid(a + b).name() << std::endl;
}
В соответствии с Stroustrup нет исключений из правила продвижения с плавающей запятой, поэтому я ожидал вывод "double" или "d".
Является ли упомянутый раздел о рекламных акциях неправильным или каким-то образом неясным? И есть ли разница в С++ 98 и С++ 11 относительно продвижения по типу?
Ответы
Ответ 1
Я не знаю, что говорит книга Страуступа, но в соответствии со стандартом float
в этом случае не будет преобразован в double
. Перед применением большинства арифметических двоичных операторов применяются обычные арифметические преобразования, описанные в 5p9:
- Если либо операнд имеет тип перечисления с областью (7.2), конверсии не выполняются; если другой операнд не имеет одного и того же типа, выражение плохо сформировано.
- Если один из операндов имеет тип long double, другой должен быть преобразован в длинный double.
- В противном случае, если один из операндов является двойным, другой должен быть преобразован в double.
- В противном случае, если любой операнд является float, другой должен быть преобразован в float.
- В противном случае интегральные акции (4.5) должны выполняться на обоих операндах. [...]
Интегральные акции - это то, что приводит к преобразованию двух short
в int
s. Но два float
не будут преобразованы в double
в соответствии с этими правилами. Если вы добавите float
в double
, float
будет преобразован в double
.
Вышеизложенное из С++ 11. С++ 03 содержит те же правила, за исключением тех, которые относятся к облачным перечислениям.
Ответ 2
Тем временем Страуструп, похоже, признал, что предложение о назначении неверно или, по крайней мере, вводит в заблуждение. Он удалил предложение о продвижении с плавающей запятой из раздела 10.5.1.
Пожалуйста, просмотрите errata третьего издания 4-го издания на веб-странице Stroustrup:
pg 267: s/Аналогично, продвижение с плавающей запятой используется для создания двойников из поплавков //
(Примечание: выражение s/regexp/replacement/похоже на семантику sed unix. Он ищет шаблон regexp и заменяет его заменой. Ничего в нашем случае.)