As other people have explained, printf doesn't need to know the size of some output buffer ahead of time because it doesn't need to allocate one when writing to a FILE* stream.
However, you might then wonder: what about functions in the printf-family that don't write to FILE* streams? What about, say, the non-standard asprintf function that returns an allocated string?
The underlying implementation for the printf family of functions can do a dry-run. That is, it can simulate doing the operation without actually writing to memory and keep track of the number of chars that it would have written. Once it computes the that number, it then can allocate a buffer of the appropriate size and repeat the operation for real. This is what a caller would do when it needs to allocate a buffer itself, such as when calling snprintf.
(You also talk about buffered I/O. While printf can use that, printf doesn't necessarily know about the buffer itself (and it probably shouldn't). You can think of it as calling fputc a bunch of times, which then writes the char to some buffer, flushing it if it's full.)