How cout is more typical than printf ()

I read it in many places, but I do not understand. Why is it said that cout is more type-safe than printf (). Just because you don’t need to write %d %c %f or it has a deeper meaning.

Thanks in advance.

+6
source share
5 answers

That's why:

 printf("%s\n", 42); // this will clobber the stream 

This will lead to a buffer overflow - the compiler usually cannot verify that the format string in the first argument to printf matches the types of subsequent arguments. It can do this in the above case - because the string is hard-coded - and some compilers do. 1 But in general, a format string can be determined at run time, so the compiler cannot verify that it is correct.


1 But these checks with special values ​​apply to printf . If you wrote your own myprintf function with the same signature as printf , there would be no way to check type safety, since the signature uses an ellipsis ... that returns all type information inside the function.

+10
source

The printf family functions are variational functions since they all use an ellipsis ... which means that an argument of type any can be passed to the function before ... There are no restrictions on the compiler, since argument types are not required . The compiler cannot enforce type safety rules, because the ellipsis ... allows ALL types to be used. The function uses the format string to accept the type of the argument (even if there is a mismatch!). The format string is read and interpreted at runtime, and by that time the compiler cannot do anything if there is a mismatch, because the code has already been compiled. Therefore, it is not type safe. By type-of-security, we usually mean that the compiler is able to check the conformity of program types by imposing rules on types of (unvalued) expressions.

Note that if there is a mismatch (which the function cannot understand!), The program enters the undefined -behavior zone, where the behavior of the program is unpredictable and theoretically anything can happen.

You can extend the same logic to any variational function functions such as scanf family.

+6
source
  • the type system guarantees correctness with std::ostream , but not printf . Konradsky answer is one example, but something like

     printf("%ld\n", 7); 

    also does not work (assuming that long and int on your system are different sizes). It can even work with one build purpose and fail with another. Trying to print typedefs like size_t has the same problem.

    This is (somewhat) resolved by the diagnostic provided by some compilers, but it does not help in the second sense:

  • systems with two types (the runtime type system used in the format string and the compilation time system used in your code) cannot be synchronized automatically. For example, printf does not interact well with templates:

     template <typename T> void print(T t) { printf("%d\n",t); } 

    you cannot do it right for all types of T - the best you can do is static_cast<int>(t) , so it will not be able to compile if T is not converted to int. Compare

     template <typename T> void print(std::ostream& os, T t) { os << t << '\n'; } 

    which selects the correct operator<< overload for any T that has one.

+3
source

As a rule, compilers cannot check arguments from printf, do not even count the number of arguments, and do not check whether they are suitable for a format string. They are “optimized” to do the job, but are a special case and may fail. Example:

 printf("%s %d\n", 1, "two", 3); 

This will compile (if the optimized compiler does not detect a failure), and at run time printf will consider the first argument (1) line and the second ("two") integer. printf won’t even notice that there is a third argument, and don’t notice if there aren’t enough arguments!

Using cout, the compiler must select a specific <<operator for each variable that you insert. Example:

 cout<<1<<"two"<<3<<endl; 

The compiler should change this on calls with the corresponding ostream&operator<<(int) and ostream&operator<<(const char*) (as well as ostream&operator<<(ios&(*)(ios&)) ).

cout will also be faster since format string interpretation is not performed.

+2
source

From the C ++ FAQ :

[15.1] Why should I use <iostream> instead of the traditional <cstdio> ?

[...]

More secure type: C, the type of the object, which is I / O'd, is known statically by the compiler. In contrast, it uses the "%" fields to dynamically determine types.

[...]

For printf compiler cannot check if the script format of the first argument matches the types of the other arguments ... In general, this is executed at runtime.

+1
source

Source: https://habr.com/ru/post/949990/


All Articles