4

printf can be accessed if you #include <stdio.h>. I like using printf because of the format specifiers, and it just feels nicer than doing std::cout << "something\n";.

#include <stdio.h>
#include <cstdlib> // to use rand()

int main() {
    int randNum = rand()%10 + 1;
    printf("Hey, we got %d!\n", randNum);
    return 0;
}

vs

#include <iostream>
#include <cstdlib> // to use rand()
using std::cout;

int main() {
    int randNum = rand()%10 + 1;
    cout << "Hey, we got " << randNum << "!\n";
    return 0;
}

But a user in a discord server that I am in said it was bad practice because "printf is unsafe, use std::cout".

A second user said it was bad because it's not type safe (the first user did mention type safety but not in depth).

The second user said,

Typesafety is enforced by the compiler. However by using a variadic function, the compiler cannot tell the type of the arguments at runtime; it can't know them in advance. The function needs some way to tell what type of arguments to expect, and the printf family of C functions did this through the format string specifiers.

So I'm looking for other alternatives.

If there are none I guess I'll just stick to std::cout

incapaz
  • 349
  • 1
  • 3
  • 11
  • 3
    Stream output (using derived classes of `std::stream`) is the common and recommended way to do output in C++. Formatting is possible using stream manipulators offered in ``. To deny it might result in fighting against wind mills... ;-) – Scheff's Cat Jun 05 '19 at 05:27
  • Output formatting using `std::cout` can get quite a pain, though. QT's QString comes with a similar typesafe function. Well, I wouldn't introduce QT just for this purpose, but if you are using it anyway... You could, too, write your own `printf` function based on variadic templates. You'd leave out the specific type identifier then, though (d, u, x, ...). – Aconcagua Jun 05 '19 at 05:28
  • 4
    Depending on the compiler you use, `printf` will be type safe in practice because many compilers can parse and check your format strings. My recommendation is to ignore iostreams; they're a mess. – melpomene Jun 05 '19 at 05:41
  • Well, there's always `putc()` and `puts()` ... :) – Jeremy Friesner Jun 05 '19 at 05:45
  • 2
    You can generally include `` for the `stdio` header file in C++. While `iostream` is the general C++ workhorse, there are a number of instances where `stdio` functions can be a more efficient approach. – David C. Rankin Jun 05 '19 at 05:55
  • Yes, printf is unsafe. A Google search will bring up relevant results, e.g. [link](https://stackoverflow.com/questions/7459630/how-can-a-format-string-vulnerability-be-exploited), which is why MS brought in a more secure replacement, [link](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/printf-s-printf-s-l-wprintf-s-wprintf-s-l?view=vs-2019). The proper replacement is iostreams. On the same subject C++11 brought with it a new template library for random numbers that does a much better job than C's rand, [link](http://www.cplusplus.com/reference/random/) – Uri Raz Jun 05 '19 at 06:41
  • @UriRaz Even the safe MS variants of printf family are variadic functions. Curious how MS would solve the main issue for being unsafe: How to assure that arguments passed to the function match the specifiers in the format string? – Aconcagua Jun 05 '19 at 06:58
  • 3
    Also note that, in some [environments](https://stackoverflow.com/questions/31882168/the-input-output-library-stdio-h-shall-not-be-used), you aren't even allowed to use `printf`. If you are looking for some alternatives, you might consider [{fmt}](https://github.com/fmtlib/fmt) too. – Bob__ Jun 05 '19 at 08:36

3 Answers3

6

The GNU C++ compiler g++ checks printf arguments at compile-time. If you specify -Wall on the command line, it issues a warning if it detects a mismatch. So if you are using this compiler, you can use printf without worrying.

Your compiler may or may not offer a similar service. But hell, use printf anyway, at least in preference to the ridiculous cout mechanism. Or for a type-safe solution, you might consider using the Boost Format library.

Edited to add: This question has a discussion that you might find interesting.

TonyK
  • 16,761
  • 4
  • 37
  • 72
2

As an alternative on embedded devices you could consider the <1KB Open Source Trice, which allows printf-like comfort also inside interrupts by delegating the printing task to the external log viewer. I developed this tool, because I found nothing better.

0

As kindly explained by @TonyK, snprintf and sprintf are used to write into a buffer and not to the standard stream. Instead of just answering the specific question, this explains a broader solution.


For a "safer" function, you could look at using snprintf where the size of the object is explicitly specified.

Without specifying the size and using printf, you have to "trust" that the provided char* is a valid C-string with terminating null character, otherwise printf will keep reading the memory.


Generally speaking, if the requirements is to only use C and only have a dependency on the associated C runtime library (glibc on Linux, msvcrt/ucrt on Windows, ...), using only C header and and using a C compiler makes sense.

If using C++ is an option, using std::cout is a natural choice as it will support displaying any object implementing the ostream::operator<<.

Answers on what is the best choice will dependent on what you try to achieve.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
J-Christophe
  • 1,975
  • 15
  • 13
  • Don't you just love these downvoters who don't explain what's wrong with the answer, so helpful. (Btw, I assume it's because your answer doesn't address the core issue of OPs question (type safety of variadic arguments), and because printf and snprintf do very different things (one writes to standard out, the other writes into a char array)). – Max Vollmer Jun 05 '19 at 05:59
  • 5
    `printf` is just as safe as `snprintf`. The `snprintf` function is provided to guard against the buffer overrun errors that `sprintf` (not `printf`) is vulnerable to. – TonyK Jun 05 '19 at 06:14
  • @Chipster: did you read my comment? Or did you just not believe it? – TonyK Jun 07 '19 at 12:32
  • 1
    @TonyK Thanks for your help clarifying, I edited my original post to make things explicit. – J-Christophe Jun 07 '19 at 19:36
  • 1
    @Chipster Thanks for your support. That said, while my post is informational, it doesn't explicitly answer the question asked. – J-Christophe Jun 07 '19 at 19:37