Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 05 Jun 2011 20:42:45 +0000
From:      "Poul-Henning Kamp" <phk@freebsd.org>
To:        Ben Laurie <ben@links.org>
Cc:        hackers@freebsd.org
Subject:   Re: int64_t and printf 
Message-ID:  <12271.1307306565@critter.freebsd.dk>
In-Reply-To: Your message of "Sun, 05 Jun 2011 21:17:45 %2B0100." <4DEBE469.5060305@links.org> 

next in thread | previous in thread | raw e-mail | index | archive | help
In message <4DEBE469.5060305@links.org>, Ben Laurie writes:
>On 05/06/2011 19:21, Poul-Henning Kamp wrote:
>> In message <4DEBC741.1020200@links.org>, Ben Laurie writes:

>> I have therefore resorted to printf'ing any typedefed integer type using
>> "%jd" and an explicit cast to (intmax_t):
>> 
>> 	printf("%-30s -> %jd -> %s\n", s, (intmax_t)t, buf);
>
>My objection to this approach is the lack of type-safety - t could be
>anything and this would continue to work.
>
>Using PRId64 at least ensures that t is of an appropriate type.

Uhm, no, it doesn't.

At best it allows the compiler to make well chosen assumptions
about what the printf(3) function does.

Printf-format warnings are usually lost as soon as you go through
stdarg/v*printf, because people don't know they should add
__printflike() and other nonportable gunk to their prototypes.

And they are totally lost if you use extended printf formatting
of any kind, because there is no way to tell the compiler that
"%Y takes a void *"

This is basically why the work I did in <printf.h> is practically
useless.

But worse: PRId64 only works if you know your variable actually is 64bit.

If you are trying to write code which works with typedefs on both
32 and 64 bit platforms you cannot know this.

It's all nice and dandy that they made a magic "z" letter for size_t,
but what about uid_t, gid_t, pid_t, off_t, ino_t, mode_t, nlink_t,
fflags_t and so on ?

You will therefore be forced to cast your argument to (int64_t)
before you can use PRId64 safely on it.

Now you have messed up the format string without loosing the cast
and now your code will DTWT once somebody typedefs pid_t to int71_t.

>Providing a better printf seems like an even smarter idea, e.g.
>
> 	printf("%-30s -> %I64d -> %s\n", s, t, buf);

Same problem as above.

There is no way to do this sanely, without involving the compiler.

At the very least, the compiler would need to mangle the format
string, so that you write:

	printf("%-30?d\n", sometype)

and the compiler replaces the '?' with whatever is suitable
for the width of the argument.

Alternatively, and more useful, would be a type-safe or at least
type-aware stdarg, so that prinf(3) could ask about the width
and type of the next argument.

Both would be wonderful additions to ISO-C but you can produce a
college fresh-man from scratch starting now, before that happens.

(See also Bjarnes approx. 1985 discussion of why C++ overloads <<
instead of providing printf(3)).

-- 
Poul-Henning Kamp       | UNIX since Zilog Zeus 3.20
phk@FreeBSD.ORG         | TCP/IP since RFC 956
FreeBSD committer       | BSD since 4.3-tahoe    
Never attribute to malice what can adequately be explained by incompetence.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?12271.1307306565>