printf – source of bugs? [closed]

I’m using a lot of printf for tracing/logging purposes in my code, I’ve found that it’s a source of programming error. I always found the insertion operator (<<) to be somewhat of a odd thing but I’m beginning to think that by using it instead I could avoid some of these bugs.

Anyone ever had a similar revelation or I’m just grasping at straws here?

Some take away points

  • My current line of thinking is that type-safety outweighs any benefit
    of using printf. The real problem is the format string and the use of
    non type-safe variadic functions.
  • Maybe I won’t be using << and the stl output stream variants but I will certainly look into using a type-safe mechanism which is very similar.
  • A lot of the tracing/logging is conditional but I’d like to always run the code to not miss bugs in tests just because it’s a rarely taken branch.

16

printf, particularly in cases where you might care about performance (such as sprintf and fprintf) is a really strange hack. It constantly amazes me that people who pound on C++ due to miniscule performance overhead related to virtual functions will then go on to defend C’s io.

Yes, in order to figure out the format of our output, something that we can know 100% at compile time, let’s parse a fricken format string at runtime inside a massively weird jump table using inscrutable format codes!

Of course these format codes couldn’t be made to match the types they represent, that would be too easy… and you’re reminded every time you lookup whether it’s %llg or %lg that this (strongly typed) language makes you figure out types manually to print/scan something, AND was designed for pre-32bit processors.

I’ll admit that C++’s handling of format width and precision is bulky and could use some syntactic sugar, but that doesn’t mean you have to defend the bizarre hack that is C’s main io system. The absolute basics are pretty easy in either language (although you should probably be using something like a custom error function/error stream for debug code anyways), the moderate cases are regex-like in C (easy to write, hard to parse/debug), and the complex cases impossible in C.

(If you use the standard containers at all, write yourself some quick templated operator<< overloads that allow you to do things like std::cout << my_list << "n"; for debug, where my_list is of type list<vector<pair<int,string> > >.)

2

Mixing C-style printf() (or puts() or putchar() or …) output with C++-style std::cout << ... output can be unsafe. If I recall correctly, they can have separate buffering mechanisms, so the output might not appear in the intended order. (As AProgrammer mentions in a comment, sync_with_stdio addresses this).

printf() is fundamentally type-unsafe. The type expected for an argument is determined by the format string ("%d" requires an int or something that promotes to int, "%s" requires a char* which must point to a correctly terminated C-style string, etc.), but passing the wrong type of argument results in undefined behavior, not a diagnosable error. Some compilers, such as gcc, do a reasonably good job of warning about type mismatches, but they can do so only if the format string is a literal or is otherwise known at compile time (which is the most common case) — and such warnings are not required by the language. If you pass the wrong type of argument, arbitrarily bad things can happen.

C++’s stream I/O, on the other hand, is much more type-safe, since the << operator is overloaded for many different types. std::cout << x doesn’t have to specify the type of x; the compiler will generate the right code for whatever type x has.

On the other hand, printf‘s formatting options are IMHO much more convenient. If I want to print a floating-point value with 3 digits after the decimal point, I can use "%.3f" — and it has no effect on other arguments, even within the same printf call. C++’s setprecision, on the other hand, affects the state of the stream, and can mess up later output if you’re not very careful to restore the stream to its previous state. (This is my personal pet peeve; if I’m missing some clean way to avoid it, please comment.)

Both have advantages and disadvantages. The availability of printf is particularly useful if you happen to have a C background and you’re more familiar with it, or if you’re importing C source code into a C++ program. std::cout << ... is more idiomatic for C++, and doesn’t require as much care to avoid type mismatches. Both are valid C++ (the C++ standard includes most of the C standard library by reference).

It’s probably best to use std::cout << ... for the sake of other C++ programmers who may work on your code, but you can use either one — especially in trace code that you’re going to throw away.

And of course it’s worth spending some time learning how to use debuggers (but that might not be feasible in some environments).

6

Your problem is most likely coming from the mixing of two very different standard output managers, each of which has it’s own agenda for that poor little STDOUT. You get no guarantees about how they are implemented, and it is perfectly possible that they set conflicting file descriptor options, both try to do different things to it, etc. Also, the insertion operators have one major over printf: printf will let you do this:

printf("%d", SomeObject);

Whereas << will not.

Note: For debugging, you don’t use printf or cout. You use fprintf(stderr, ...) and cerr.

4

There are many groups – for example google – that don’t like streams.

http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Streams

(Pop open the triangle thingy so you can see the discussion.) I think the google C++ style guide has LOTS of very sensible advice.

I think the tradeoff is that streams are safer but printf is clearer to read (and easier to get exactly the formatting you want).

1

printf can cause bugs due to the lack of type safety. There are a few ways of addressing that without switching to iostream‘s << operator and more complicated formatting:

  • Some compilers (such as GCC and Clang) can optionally check your printf format strings against the printf arguments and can display warnings such as the following if they don’t match.
    warning: conversion specifies type 'int' but the argument has type 'char *'
  • The typesafeprintf script can preprocess your printf-style calls to make them type-safe.
  • Libraries such as Boost.Format and FastFormat let you use printf-like format strings (Boost.Format’s in particular are almost identical to printf) while keeping iostreams‘ type safety and type extensibility.

Printf syntax is basically fine, minus some of obscure typing. If you think it’s wrong why C#, Python and other languages use the very similar construct? The problem in C or C++: it’s not part of a language and thus not checked by compiler for correct syntax(*) and not decomposed into series of native calls if optimizing for speed. Note that if optimizing for size, printf calls might turn out more efficient!
C++ streaming syntax is imho anything but good. It works, type-safety is there, but the verbose syntax… bleh. I mean I use it, but with no joy.

(*) some compilers DO this checking plus almost all static analysis tools (I use Lint and never had any problem with printf since).

1

printf is, in my own opinion, a far more flexible output tool for dealing with variables than any of the CPP stream outputs. For example:

printf ( "%d in ANSI = %cn", j, j ); /* Perfectly valid... if a char ISN'T printing right, I'd just check the integer value to make sure it was okay. */

However, where you may want to use the CPP << operator is when you overload it for a particular method… for example to get a dump of an object that holds the data of a particular person, PersonData….

ostream &operator<<(ostream &stream, PersonData obj)
{
 stream << "nName: " << name << endl;
 stream << " Number: " << phoneNumber << endl;
 stream << " Age: " << age << endl;
 return stream;
}

For that, it would be far more effective to say (assuming a is an object of PersonData)

std::cout << a;

than:

printf ( "Name: %sn Number: %sn Age: %dn", a.name, a.number, a.age );

The former is far more in-line with the principle of encapsulation (No need to know the specifics, private member variables), and is also easier to read.

You are not supposed to use printf in C++. Ever. The reason is, as you correctly noted, that it’s a source of bugs and the fact that printing custom types, and in C++ almost everything should be custom types, is pain. C++ solution is the streams.

However there is a critical problem that makes streams unsuitable for any and user-visible output! The problem is translations. Borrowing example from the gettext manual say you want to write:

cout << "String '" << str << "' has " << str.size() << " charactersn";

Now the German translator comes along and says: Ok, in German, the message should be

n Zeichen lang ist die Zeichenkette ‘s

And now you are in trouble, because he needs the pieces shuffled around. It should be said, that even many implementation of printf have problem with this. Unless they support the extension so you can use

printf("%2$d Zeichen lang ist die Zeichenkette '%1$s'", ...);

The Boost.Format supports printf-style formats and has this feature. So you write:

cout << format("String '%1' has %2 charactersn") % str % str.size();

Unfortunately it carries a bit of performance penalty, because internally it creates a stringstream and uses the << operator to format each bit and in many implementation the << operator internally calls sprintf. I suspect more efficient implementation would be possible if really desired.

You are doing a lot of useless work, beside the fact that stl is evil or not, debug your code with a series of printf only add 1 more level of possible failures.

Just use a debugger and read something about Exceptions and how to catch and throw them; try to not be more verbose than you actually need to be.

PS

printf is used in C, for the C++ you have std::cout

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật