简体   繁体   中英

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

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?

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.

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.

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.[...]

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;
}

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.

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);

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.

Have one of your numbers be a floating point value:

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

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

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM