Почему этот вывод одного и того же выражения из printf отличается от cout?
Я использую Visual C++ 2012 и компилирую из командной строки следующие файлы:
#include <stdio.h>
int main()
{
printf("%.5f", 18/4+18%4);
return 0;
}
связывание с MSVCRT.LIB, а не LIBCMT, чтобы избежать ошибки выполнения R6002.
Выходное значение для этой программы равно 0.00000.
однако, если я выполняю то же самое в C++
#include <iostream>
using namespace std;
int main()
{
cout << 18/4+18%4 << endl;
return 0;
}
теперь он печатает 6, как и должно.
в чем разница? Это связано с самими языками (C vs C++) или с выходом методы (cout vs printf), или это просто причуда с MSVC?
9 ответов
выражение 18/4+18%4
оценивает в int
, и вы запрашиваете поплавок. Вы всегда должны компилировать с включенными предупреждениями и обращать на них внимание (они говорят предупреждение-это ошибка ждет, и они правы).
это то, что мой компилятор (GCC 4.8.1) говорит мне (и даже без принуждения -Wall
):
warning: format ‘%.5f’ expects type ‘double’, but argument 2 has type ‘int’
С другой стороны,std::cout<<
операция способна вывести тип вашего выражения и правильно передать его в ваш экран.
функция C передается целым числом, но вы говорите это (с %f
) ожидать числа с плавающей запятой двойной точности, поэтому он терпит неудачу. Функция C++ знает, что ей передается целое число, поэтому она работает правильно.
на C пример этого выражения 18/4+18%4
оценивают в int так как все операнды целочисленные константы но вы указываете, что это двойной to printf
и поэтому он будет обработан неправильно. С другой стороны, если вы используете плавающие константы в части деления выражения, например 18.0/4+18%4
все выражение было бы оценено в a двойной. В качестве альтернативы вы могли бы использовать "%d"
в спецификаторе формата.
это тоже неопределенное поведение неправильно указать формат в printf
и это также демонстрирует, почему важно строить с предупреждениями, используя gcc -Wall
Я получаю следующее предупреждение(видеть live):
warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’
на C++ std:: cout ' s оператор есть перегрузка для int
и поэтому это будет называться в данном случае. Мы можем видеть эту перегрузку, и многие другие требуются проект стандарта C++, в секции 27.7.3.1
шаблон класса basic_ostream мы находим следующее объявление оператор:
basic_ostream<charT,traits>& operator<<(int n);
для полноты, возвращаясь к неопределенному поведению,проект стандарта C99 в разделе 7.19.6.1
функция fprintf, который printf
'ы раздел ссылается на строку формата paragraph 9 говорит:
если спецификация преобразования является недопустимым, поведение неопределено.[...]
выражение
18 / 4 + 18 % 4
оценивает в int.
но printf формат строки "%.5Ф" ожидает двойная.
С помощью c++ и ostreams язык может автоматически определять тип вывода.
просто измените свой C-код на следующий:
#include <stdio.h>
int main()
{
printf("%d", 18 / 4 + 18 % 4);
return 0;
}
Другие правильно указали на несоответствие int/double в вашем операторе printf (). Я просто хочу прокомментировать ваше заявление", - говорится в сообщении MSVCRT.LIB, а не LIBCMT, чтобы избежать ошибки выполнения R6002."Такая простая программа не должна чрезмерно облагать налогом среду выполнения, поэтому такая ошибка выполнения должна быть красным флагом неопределенного поведения в вашем коде.
быстрый Google "MSVCRT R6002" говорит:
C Ошибка Времени Выполнения R6002 поддержка с плавающей запятой не загружена
необходимая библиотека с плавающей запятой не была связана. Исправить, проверив следующие возможные причины
- программа была скомпилирована или связана с опцией, такой как /FPi87, для которой требуется сопроцессор, но программа была запущена на машине, на которой не был установлен сопроцессор.
- строка формата для функции printf_s или scanf_s содержит формат с плавающей запятой спецификация и программа не содержали никаких значений или переменных с плавающей запятой.
- компилятор минимизирует размер программы, загружая поддержку с плавающей запятой только при необходимости. Компилятор не может обнаружить спецификации формата с плавающей запятой в строках формата, поэтому он не загружает необходимые процедуры с плавающей запятой.
- используйте аргумент с плавающей запятой для соответствия спецификации формата с плавающей запятой или выполните назначение с плавающей запятой в другом месте программы. Это приводит к загрузке поддержки с плавающей запятой.
- в программе на смешанном языке библиотека C была указана перед библиотекой FORTRAN, когда программа была связана. Повторно свяжите и укажите библиотеку C последней.
урок здесь, конечно, заключается в том, что вы должны уделять пристальное внимание предупреждениям компилятора и времени выполнения и ошибкам. Когда вы сомневаетесь, всегда предполагайте, что проблема в вашем коде, а не в компилятор.
В C, поскольку вы явно указываете плавающую точку ("%f") в описателе формата printf, поэтому он ожидает аргумент с плавающей точкой. Но вы даете ему аргумент "int", следовательно, проблема.
в зависимости от того, что вы пытаетесь сделать, вы можете:
1) литье (в противном случае целое) выражение для float
и/или
2) с помощью setprecision в поток cout, так же, как вы бы использовать "%.5Ф" в C:
#include <iostream>
using namespace std;
int main()
{
float x = 18/4+18%4;
std::cout << std::setprecision(5) << x << endl;
return 0;
}
3) Если вы хочу целое число, используйте printf ("%d", 18/4+18%4);
если вы хотите такое же поведение (и ответ) вы бы лучше код
printf("%d\n", 18/4 + 18%4);
чтобы получить ответ int Вместо ответа с плавающей запятой. Вы получите тот же результат, что и <<
выбранный оператор
ostream& std::operator<<(ostream&, const int);
в противном случае, вы можете использовать явно
printf("%.5f\n", (double)(18/4 + 18%4));
и 6.00000
результат.
пусть одно из ваших чисел будет значением с плавающей запятой:
#include <stdio.h>
int main()
{
printf("%.0f", 18/4.0+18%4);
return 0;
}
одной из возможных альтернатив является типизация литералов (или самого выражения):
#include <stdio.h>
int main(void)
{
printf("%.5f", (float)18/4+18%4);
return 0;
}