Why does this output of the same expression from printf differ from cout?

只谈情不闲聊 提交于 2019-12-04 02:47:17

问题


I'm using Visual C++ 2012 and compiling from the command line the following files:

#include <stdio.h>
int main()
{
    printf("%.5f", 18/4+18%4);
    return 0;
} 

Linking with MSVCRT.LIB rather than LIBCMT to avoid runtime error R6002.
The value that is output is 0.00000 for this program.

However, if I perform the exact same thing in C++

 #include <iostream>
 using namespace std;
 int main()
 {
      cout << 18/4+18%4 << endl;
      return 0;
 }

Now, it prints out 6, like it should.

What's the difference? Is it to do with the languages themselves (C vs C++) or the output methods (cout vs printf), or is it just a quirk with MSVC?


回答1:


The expression 18/4+18%4 evaluates to an int, and you are requesting a float. You should always compile with warnings enabled, and pay attention to them (they say a warning is a bug waiting to happen, and they are right).

This is what my compiler (GCC 4.8.1) tells me (and even without enforcing -Wall):

warning: format ‘%.5f’ expects type ‘double’, but argument 2 has type ‘int’

On the other hand, the std::cout<< operation is able to deduce the type of your expression and correctly stream it to your screen.




回答2:


The C function is being passed an integer, but you are telling it (with %f) to expect a double-precision floating point number, so it fails. The C++ function knows that it is being passed an integer, so it works properly.




回答3:


In the C example this expression 18/4+18%4 will evaluate to an int since all the operands are integer constants but you are specifying that it is a double to printf and therefore it is will be processed incorrectly. On the other hand if you had used a Floating constant in the division part of the expression for example 18.0/4+18%4 the whole expression would have evaluated to a double. Alternatively you could have used "%d" in the format specifier as well.

This is also undefined behavior to incorrectly specify the format to printf and this also demonstrates why building with warnings is important, using gcc -Wall I receive the following warning(see it live):

warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ 

In C++ std::cout's operator<< has an overload for int and therefore that will be called in this case. We can see this overload an many others are required by the C++ draft standard, in section 27.7.3.1 Class template basic_ostream we find the following operator declaration:

basic_ostream<charT,traits>& operator<<(int n);

For completeness sake, circling back to the undefined behavior, the C99 draft standard in section 7.19.6.1 The fprintf function which printf's section refers back to for the format string paragraph 9 says:

If a conversion specification is invalid, the behavior is undefined.[...]




回答4:


The expression

18 / 4 + 18 % 4

evaluates to an int.

But the printf format string "%.5f" expects a double.

With c++ and ostreams, the language can determine the output type automatically.

Just change your C-code to following:

#include <stdio.h>
int main()
{
    printf("%d", 18 / 4 + 18 % 4);
    return 0;
}



回答5:


Others have correctly pointed out the int/double mismatch in your printf() statement. I just want to comment on your statement, "Linking with MSVCRT.LIB rather than LIBCMT to avoid runtime error R6002." A program this simple should not unduly tax the runtime environment, so a runtime error like this should be a red flag of undefined behavior in your code.

A quick Google of "MSVCRT R6002" says:

C Run-Time Error R6002 floating-point support not loaded

The necessary floating-point library was not linked. To fix by checking the following possible causes

  1. The program was compiled or linked with an option, such as /FPi87, that requires a coprocessor, but the program was run on a machine that did not have a coprocessor installed.
  2. A format string for a printf_s or scanf_s function contained a floating-point format specification and the program did not contain any floating-point values or variables.
  3. The compiler minimizes a program's size by loading floating-point support only when necessary. The compiler cannot detect floating-point format specifications in format strings, so it does not load the necessary floating-point routines.
  4. Use a floating-point argument to correspond to the floating-point format specification, or perform a floating-point assignment elsewhere in the program. This causes floating-point support to be loaded.
  5. In a mixed-language program, a C library was specified before a FORTRAN library when the program was linked. Relink and specify the C library last.

The lesson here, of course, is that you should pay close attention to compiler and runtime warnings & errors. When in doubt, always assume the problem is in your code, not in the compiler's.




回答6:


In C because you explicitly specify floating point ("%f") in your printf format specifier, so it's expecting a floating point argument. But you're giving it an "int" argument, hence the problem.

Depending on what you're trying to do, you can:

1) Casting your (otherwise integer) expression to float

and/or

2) Using setprecision in your cout stream, just as you'd use "%.5f" in C:

#include <iostream>
using namespace std;
int main()
{
   float x = 18/4+18%4;
   std::cout << std::setprecision(5) << x << endl;
   return 0;
}

3) If you want integer, use printf ("%d", 18/4+18%4);




回答7:


If you want the same behaviour (and response) you'd better to code

printf("%d\n", 18/4 + 18%4);

to get an int response instead of a floating point one. You'll get the same result as << operator selected is

ostream& std::operator<<(ostream&, const int);

Otherwise, you can use explicitly

printf("%.5f\n", (double)(18/4 + 18%4));

to get 6.00000 result.




回答8:


Have one of your numbers be a floating point value:

#include <stdio.h>
int main()
{

    printf("%.0f", 18/4.0+18%4);
    return 0;
} 



回答9:


One possible alternative is, typecasting the literals (or the expression itself):

#include <stdio.h>

int main(void)
{
    printf("%.5f", (float)18/4+18%4);
    return 0;
}


来源:https://stackoverflow.com/questions/19102778/why-does-this-output-of-the-same-expression-from-printf-differ-from-cout

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!