В такой программе на Си double x = 1 x %= 1. получаю сообщение об ошибке http://ideone.com/dDurEH invalid operands to binary % (have 'double' and 'long double') из которого следует, что выражение 1. имеет тип long double. Тот же код, но на плюсах показывает просто double http://ideone.com/nd49YK: invalid operands of types 'double' and 'double' to binary 'operator%' Да и такая проверка на плюсах тоже за double http://ideone.com/HCw0GG: auto x = 1. cout << sizeof (double) << ' ' // 8 << sizeof (long double) << ' ' // 12 << sizeof x << ' ' // 8 << sizeof 1. << endl // 8 <br>Получается, С++ выводит тип double, а не long double. Итак, это одни из различий Си и Си++ или же косяк компилятора? Какой правильный тип у константы 1. и зависит ли он от языка?
Ответ Константа вида 1. имеет тип double как в C++, так и в C. C 6.4.4.2/4: An unsuffixed floating constant has type double. If suffixed by the letter for F, it has type float. If suffixed by the letter l or L, it has type long double. C++ 2.14.4/1: The type of a floating literal is double unless explicitly specified by a suffix.
Компилятор, используемый на ideone.com имеет версию 5.1.1 20150711. Так что может иметь смысл погонять её локально, если у кого есть возможность. Похожий компилятор на goodbolt (5.1) выдает ошибку с правильными типами: error: invalid operands of types 'double' and 'double' to binary 'operator%' error: in evaluation of 'operator%=(double, double)'
Возможная причина кроется в значении FLT_EVAL_METHOD, которое задает точность вычислений для внутренних операций. Для ideone это значение равно 2, т.к. используется 32-битный компилятор: For gcc, FLT_EVAL_METHOD == 2 is the default on 32 bit x86 Т.е. все вычисления с плавающей точкой опираются на тип long double. Хотя, по правде говоря, это и не должно влиять на тип вещественной константы. Как оказалось, изменить значение FLT_EVAL_METHOD с 0 на 2 на 64 bit компиляторе g++ можно путём добавления ключа -mfpmath=387: #include #include int main() { // 1 % 1. printf( "%d ", FLT_EVAL_METHOD) } Результат: 2
В этом случае сообщение об ошибке для второго аргумента также выводит тип long double как и исходное на ideone (для 32 bit): invalid operands to binary % (have 'int' and 'long double')
Для clang нужен другой ключ: -mno-sse. При этом диагностическое сообщение уже для обоих типов выводит double: invalid operands to binary expression ('double' and 'double')
При этом первый, как мне кажется, должен всё же был остаться int. Подводя итог, можно сказать, что оба компилятора в диагностических сообщениях имеют проблемы с выводом исходного типа операндов.