9

Shouldn't the return be of type size_t instead? Because the size of objects in C is of this type, including the string passed to printf.

15
  • 7
    It's just historical - you can't easily change these things after the fact without breaking existing code, and there is no real motivation when the output from a single printf is unlikely to exceed 32k, let alone 2G. Commented Aug 17, 2017 at 16:19
  • 6
    Remember that the printf return value can be negative. The size_t type is unsigned. Commented Aug 17, 2017 at 16:20
  • 2
    Back when printf was designed, there was no size_t and people used ints. Changing it to size_t would break some old code, so they can’t do that; if they were to design printf from scratch now they probably would use size_t. Commented Aug 17, 2017 at 16:21
  • 1
    @BiteBytes: if you were defining the stdio API now rather than 40 years ago you might well make it size_t or ssize_t, but it really makes no difference for any real world example that I can think of. Commented Aug 17, 2017 at 16:21
  • 1
    size_t isn't good cause you need a way to signal errors, and you can't use 0 for that because 0 is kind of a legitimate output count for printf. I think I'd use ` ssize_t/ptrdiff_t/long` if I was doing my own printf. Commented Aug 17, 2017 at 16:29

3 Answers 3

10

Why printf returns an int in C?
Shouldn't be of type size_t instead?

It could have been, but certainly an early design decision was to accommodate a return value of the negative EOF to indicate error.

size_t was something of an afterthought in early design choices. Many functions used int where size_t is used now in those pre-standard days.


fprintf() has an environmental limit "The number of characters that can be produced by any single conversion shall be at least 4095.", so any print that is attempting long output may run into that limit before INT_MAX/SIZE_MAX concerns.

Sign up to request clarification or add additional context in comments.

8 Comments

@Jean-FrançoisFabre Added note: in 1970, the price of RAM was about $0.70, about 1/2 labor hour per byte. Early design choices need to consider the very expensive cost of computers and tactics used to lessen code/memory space. int is simple.
So printf, for one reason, or another, doesn't comply to the standard? Because it uses an int to hold the number of characters.
@BiteBytes printf() an extraordinary common function in those pre-standard days (1970s - 1989), became the target to match once the standard 1989 was created. That creation did not attempt to break existing practice where it could avoid it. printf() complies to the standard because it is the standard on which C89 was based.
Ok, but what is the right way to check the return of snprintf? The "obvious" way: char buff[N]; size_t sz = sizeof(buff); int n = snprintf(buff, sz, "..."); if (n < sz) ... gives rise to warnings about comparing signed and unsigned.
@JohnHascalln Note that n < 0 indicates an encoding error. if (n < 0 || (uintmax_t) n >= sz) error(); should certainly cover all platforms.
|
1

You're largely right - actually printf should return a larger type, since it's theoretically possible to output many more bytes than the size of the largest object that can fit in memory, e.g. printf("%s%s", largest_string, largest_string) or even more trivial examples using field widths/precisions.

The reason is just a historical mistake that we're stuck with. It's particularly bad with snprintf, which is artificially limited to INT_MAX and is forced to return an error if you attempt to create a longer string with it.

4 Comments

There is still the problem of returning negative numbers. To indicate error. If it was up to right now to redesign it, what would you do?
@BiteBytes: Either use a type sufficiently large that the signed form of the type could be used, or use (T)-1, where T is an unsigned type, as the error indication. Note that this works conveniently with snprintf where retval>=n is the error condition (truncation or error causing negative return) that you need to check for anyway.
@R.. Use (T)-1 is a good idea. int retval = snprintf(... size_t n, ... and retval>=n works well aside from fantasy platforms where INT_MAX > SIZE_MAX for the retval>=n is a signed compare. error = retval < 0 || retval >= n; always works.
@chux: Indeed, fantasy platforms are a problem there, but it wouldn't be a problem if snprintf actually returned size_t or some unsigned type.
0

Back then compilers did not require a function declaration in order to call a function. The return type of a function without declaration or with unspecified return type is int - the implicit int rule. Some code called printf without bothering with pesky #include <stdio.h>.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.