Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

printf with size_t, time_t, etc.

3,728 views
Skip to first unread message

Urs Thuermann

unread,
Sep 5, 1996, 3:00:00 AM9/5/96
to

I hope this isn't a FAQ. I haven't seen it addressed in one.

What is the portable way to output a value of type size_t? On some
systems (e.g. 16 bit machines) size_t is typically typedefed as
unsigned long, on others it is unsigned int. How do I know which
conversion specifier in printf, i.e. %u or %lu should be used.
The same problem occurs with time_t, ptrdiff_t, ...

urs

Hans Steffani

unread,
Sep 5, 1996, 3:00:00 AM9/5/96
to

thue...@ibr.cs.tu-bs.de (Urs Thuermann) writes:

What about
size_t val;

printf("%lu\n", (unsigned long)size_t);

hfs

[F'up,CC]
--
Hans Friedrich Steffani
Institut fuer Elektrische Maschinen und Antriebe, TU Chemnitz-Zwickau
mailto:hans.s...@e-technik.tu-chemnitz.de
http://www.tu-chemnitz.de/~hfst/

r...@aussie.com

unread,
Sep 5, 1996, 3:00:00 AM9/5/96
to

> thue...@ibr.cs.tu-bs.de (Urs Thuermann) writes:
> I hope this isn't a FAQ. I haven't seen it addressed in one.
>
> What is the portable way to output a value of type size_t? On some
> systems (e.g. 16 bit machines) size_t is typically typedefed as
> unsigned long, on others it is unsigned int. How do I know which
> conversion specifier in printf, i.e. %u or %lu should be used.
> The same problem occurs with time_t, ptrdiff_t, ...
>
> urs
>
>>>>


Since size_t is an unsigned integer type, cast it to unsigned long and use
%lu. Similarly, ptrdiff_t is a signed integer type so cast it to signed long
and use %ld.

For things like clock_t and time_t you are out of luck since these could be
floating-point or integer types. These are intended to be magic cookies for
internal use only and to accomodate the variety of prior art, not for I/O.


Rex

----------------------------------------------------------------------------
+1 703 860-0091 | Rex Jaeschke | C and C++ Seminars
FAX +1 703 860-3008 | 2051 Swans Neck Way | and Consulting
r...@aussie.com | Reston, Virginia 20191-4023, USA |
----------------------------------------------------------------------------
Chair of X3J11 (ANSI C) and participant in SC22/WG14 (ISO C). Columnist for
NT Developer and VC++ Professional.
----------------------------------------------------------------------------


Peter Shenkin

unread,
Sep 5, 1996, 3:00:00 AM9/5/96
to

In article <50mnhh$g...@narses.hrz.tu-chemnitz.de>,
Hans Steffani <hf...@hrz.tu-chemnitz.de> wrote:
>thue...@ibr.cs.tu-bs.de (Urs Thuermann) writes:

>>What is the portable way to output a value of type size_t? ...

>What about
>size_t val;
>
>printf("%lu\n", (unsigned long)size_t);

There are two difficulties, it seems to me. Recall that
the cast rules for stdarg functions imply a certain type
of promotion, even if the user applies a specific cast first.
Thus, it seems to me, the explicit cast to (unsigned long)
is redundant. There may be other cases where it's not
redundant, though I can't think of any.

The real difficulty is how to know to write "%lu" in the format.
The only way to know this is to look in the .h file where
size_t is typedef'ed, and see what it is defined to be.

This is a major problem in the use of typedef's in C. They're
great for simplifying complex declarations and for writing
self-documenting code, but the "type hiding" that they
also are said to be good for breaks down when it comes to
IO.

For instance, suppose you have code that looks like this:

typedef float My_real_type;
...
My_real_type x;
scanf( "%f", &x );
...

Now, later, you want to change the typedef to read as
follows:

typedef double My_real_type;

You still have to go through all the code and correct your
scanf's to agree with the new typedef. This cannot be
made automatic in C, unfortunately.

-P.


--
********************* (Note new snail-mail address.) **********************
* Peter S. Shenkin, Chemistry, Columbia U., 3000 Broadway, Mail Code 3153,*
** NY, NY 10027; she...@columbia.edu; (212)854-5143; FAX: 678-9039 ***
MacroModel WWW page: http://www.cc.columbia.edu/cu/chemistry/mmod/mmod.html

Dennis Yelle

unread,
Sep 5, 1996, 3:00:00 AM9/5/96
to

In article <50nd82$i...@sol.ctr.columbia.edu> she...@still3.chem.columbia.edu (Peter Shenkin) writes:
>In article <50mnhh$g...@narses.hrz.tu-chemnitz.de>,
>Hans Steffani <hf...@hrz.tu-chemnitz.de> wrote:
>>thue...@ibr.cs.tu-bs.de (Urs Thuermann) writes:
>
>>>What is the portable way to output a value of type size_t? ...
>
>>What about
>>size_t val;
>>
>>printf("%lu\n", (unsigned long)val);
^^^

>There are two difficulties, it seems to me. Recall that
>the cast rules for stdarg functions imply a certain type
>of promotion, even if the user applies a specific cast first.
>Thus, it seems to me, the explicit cast to (unsigned long)
>is redundant.

It is not redundant in general, because in some compilers,
size_t is unsigned int, and unsigned long is longer than unsigned int.
This is true for most 16 bit compilers, size_t is 16 bits, long is 32 bits.
The above printf works in all ANSI compilers.

>The real difficulty is how to know to write "%lu" in the format.
>The only way to know this is to look in the .h file where
>size_t is typedef'ed, and see what it is defined to be.

No. You write %lu because you cast to unsigned long.
You cast to unsigned long because it is the shortest type
that is long enough in all compilers. You DON'T go looking
in the .h file, because that does NOT tell you what all
compilers do, it only tells you what one specific compiler does.

>This is a major problem in the use of typedef's in C. They're
>great for simplifying complex declarations and for writing
>self-documenting code, but the "type hiding" that they
>also are said to be good for breaks down when it comes to
>IO.
>
>For instance, suppose you have code that looks like this:
>
>typedef float My_real_type;
>...
> My_real_type x;
> scanf( "%f", &x );
> ...

Rule 1: Don't use scanf().
Rule 2: Don't use gets().

So the above should be changed to use fgets() and strtod().
strtod() returns double which should be casted(sp?) to My_real_type.
If you do this a lot, you might write get_my_real_type() which
would return a My_real_type and cut down on the number
of casts.

>Now, later, you want to change the typedef to read as
>follows:
>
>typedef double My_real_type;
>
>You still have to go through all the code and correct your
>scanf's to agree with the new typedef. This cannot be
>made automatic in C, unfortunately.

This is not a problem if you use fgets() and strtod() instead
of scanf() which should never be used in new code.

--
den...@netcom.com (Dennis Yelle)
"You must do the thing you think you cannot do." -- Eleanor Roosevelt

Dennis Yelle

unread,
Sep 5, 1996, 3:00:00 AM9/5/96
to

In article <50mp2s$j...@news0-alterdial.uu.net> r...@aussie.com writes:
>
>For things like clock_t and time_t you are out of luck since these could be
>floating-point or integer types. These are intended to be magic cookies for
>internal use only and to accomodate the variety of prior art, not for I/O.
>
>Rex
>
>----------------------------------------------------------------------------
> +1 703 860-0091 | Rex Jaeschke | C and C++ Seminars
>FAX +1 703 860-3008 | 2051 Swans Neck Way | and Consulting
> r...@aussie.com | Reston, Virginia 20191-4023, USA |
>----------------------------------------------------------------------------
>Chair of X3J11 (ANSI C) and participant in SC22/WG14 (ISO C). Columnist for
>NT Developer and VC++ Professional.
>----------------------------------------------------------------------------

Well, you are on X3J11 and I am not, but I cannot believe that
there is a current compiler that would fail to give the
right result if a clock_t or a time_t was cast to a double and
printed with %f. Is there anything in the standard that says
that I am in trouble if I do this?

Obviously, I would probably divide the clock_t by
CLOCKS_PER_SEC before showing it to most people, but
I don't see why I am REQUIRED to do it.

Hans Steffani

unread,
Sep 6, 1996, 3:00:00 AM9/6/96
to

she...@still3.chem.columbia.edu (Peter Shenkin) writes:

>In article <50mnhh$g...@narses.hrz.tu-chemnitz.de>,
>Hans Steffani <hf...@hrz.tu-chemnitz.de> wrote:
>>thue...@ibr.cs.tu-bs.de (Urs Thuermann) writes:

>>>What is the portable way to output a value of type size_t? ...

>>What about
>>size_t val;
>>
>>printf("%lu\n", (unsigned long)size_t);

>The real difficulty is how to know to write "%lu" in the format.
>The only way to know this is to look in the .h file where
>size_t is typedef'ed, and see what it is defined to be.

No. (unsigned long)size_t has the type unsigned long and
unsigned longs have to print with %lu. If there is some
casting by propagation rules it will happen as to every
other argument of type unsigned long.

>You still have to go through all the code and correct your
>scanf's to agree with the new typedef. This cannot be
>made automatic in C, unfortunately.

This is correct, but the orignal problem was a printf().

h.f.s.

r...@aussie.com

unread,
Sep 6, 1996, 3:00:00 AM9/6/96
to

> den...@netcom.com (Dennis Yelle) writes:
> In article <50mp2s$j...@news0-alterdial.uu.net> r...@aussie.com writes:
> >
> >For things like clock_t and time_t you are out of luck since these could
be
> >floating-point or integer types. These are intended to be magic cookies
for
> >internal use only and to accomodate the variety of prior art, not for I/O.
> >
> >Rex
> >
> >
> Well, you are on X3J11 and I am not, but I cannot believe that
> there is a current compiler that would fail to give the
> right result if a clock_t or a time_t was cast to a double and
> printed with %f. Is there anything in the standard that says
> that I am in trouble if I do this?
>
> Obviously, I would probably divide the clock_t by
> CLOCKS_PER_SEC before showing it to most people, but
> I don't see why I am REQUIRED to do it.
>
> --
> den...@netcom.com (Dennis Yelle)
> "You must do the thing you think you cannot do." -- Eleanor Roosevelt
>
>>>>

Consider the case of a machine with 64-bit ints and 64-bit IEEE doubles. You
lose significant digits when casting large integer values to double. So yes,
you can do the cast but you may only get an approximation of the original
value. Strictly speaking we shoul be using long double instead of double but
on many implementations that's a synonym for double (e.g., Alpha, which does
not support extended IEEE precision in h/w).


Rex


Carlie Coats

unread,
Sep 9, 1996, 3:00:00 AM9/9/96
to

In article <50ogjn$p...@narses.hrz.tu-chemnitz.de>,
Hans Steffani <hf...@hrz.tu-chemnitz.de> wrote:

:she...@still3.chem.columbia.edu (Peter Shenkin) writes:
:
:>In article <50mnhh$g...@narses.hrz.tu-chemnitz.de>,
:>Hans Steffani <hf...@hrz.tu-chemnitz.de> wrote:
:>>thue...@ibr.cs.tu-bs.de (Urs Thuermann) writes:
:
:>>>What is the portable way to output a value of type size_t? ...
:
:>>What about
:>>size_t val;
:>>
:>>printf("%lu\n", (unsigned long)size_t);
:
:>The real difficulty is how to know to write "%lu" in the format.
:>The only way to know this is to look in the .h file where
:>size_t is typedef'ed, and see what it is defined to be.
:
:No. (unsigned long)size_t has the type unsigned long and
:unsigned longs have to print with %lu. If there is some
:casting by propagation rules it will happen as to every
:other argument of type unsigned long.
:
:>You still have to go through all the code and correct your
:>scanf's to agree with the new typedef. This cannot be
:>made automatic in C, unfortunately.
:
:This is correct, but the orignal problem was a printf().

But where is the guarantee that size_t fits into (unsigned long)??
Suppose instead it requires (unsigned long long long) or some other
such idiocy??

Geoff Rimmer

unread,
Sep 9, 1996, 3:00:00 AM9/9/96
to Peter Shenkin

Peter Shenkin wrote:
> typedef float My_real_type;

> My_real_type x;
> scanf( "%f", &x );
>
> Now, later, you want to change the typedef to read as
> follows:
>
> typedef double My_real_type;
>
> You still have to go through all the code and correct your
> scanf's to agree with the new typedef. This cannot be
> made automatic in C, unfortunately.

Let the power of gcc 2.7.2 amaze you!

$ cat foo.c
#include <stdio.h>

extern int
main( void )
{
typedef double My_real_type;


My_real_type x;
scanf( "%f", &x );

return 0;
}
$ gcc -Wformat -c foo.c
foo.c: In function `main':
foo.c:8: warning: float format, My_real_type arg (arg 2)
$


Cheers
Geoff
--
s...@quango.demon.co.uk
http://www.quango.demon.co.uk

Dan Pop

unread,
Sep 9, 1996, 3:00:00 AM9/9/96
to

In <511buo$m...@inxs.ncren.net> co...@mcnc.org (Carlie Coats) writes:

>But where is the guarantee that size_t fits into (unsigned long)??

Right into the standard:

size_t

which is the unsigned integral type of the result of the sizeof
operator; ^^^^^^^^^^^^^^^^^^^^^^

>Suppose instead it requires (unsigned long long long) or some other
>such idiocy??

unsigned long long long (or some other such idiocy) is not an unsigned
integral type. The only unsigned integral types in C are:

unsigned char
unsigned short
unsigned int
unsigned long

It is guaranteed that size_t is one of these types, because this list
is exhaustive.

Dan
--
Dan Pop
CERN, CN Division
Email: Dan...@cern.ch
Mail: CERN - PPE, Bat. 31 R-004, CH-1211 Geneve 23, Switzerland

Zefram

unread,
Sep 10, 1996, 3:00:00 AM9/10/96
to

Carlie Coats <co...@mcnc.org> wrote:
>But where is the guarantee that size_t fits into (unsigned long)??

In the Standard. size_t must be an unsigned integral type.

>Suppose instead it requires (unsigned long long long) or some other
>such idiocy??

There's no such type. size_t must be one of unsigned char, unsigned
short, unsigned int or unsigned long. unsigned long can represent all
values representable in any of these types, and it is the only type
with this property.

Nit-picky question: can size_t be char, if char is unsigned?

-zefram

Dan Pop

unread,
Sep 10, 1996, 3:00:00 AM9/10/96
to

>Nit-picky question: can size_t be char, if char is unsigned?

The following paragraph suggests that the answer is no:

The type char, the signed and unsigned integer types, and the
floating types are collectively called the basic types.

There are other paragraphs enforcing this conclusion in ANSI Classic
3.1.2.5. char is an integral type, but its neither signed nor unsigned :-)

Clive D.W. Feather

unread,
Sep 11, 1996, 3:00:00 AM9/11/96
to

In article <1996Sep10.1...@dcs.warwick.ac.uk>, Zefram
<A.M...@dcs.warwick.ac.uk> writes

>There's no such type. size_t must be one of unsigned char, unsigned
>short, unsigned int or unsigned long.
[...]

>Nit-picky question: can size_t be char, if char is unsigned?

No. The 4 types you mention are the only 4 unsigned integral types.
"char" is neither a signed nor an unsigned integral type.

--
Clive D.W. Feather | Associate Director | Director
Tel: +44 181 371 1138 | Demon Internet Ltd. | CityScape Internet Services Ltd.
Fax: +44 181 371 1150 | <cl...@demon.net> | <cd...@cityscape.co.uk>
Written on my laptop - please reply to the Reply-To address <cl...@demon.net>

Peter Shenkin

unread,
Sep 11, 1996, 3:00:00 AM9/11/96
to

In article <3234A3EB...@quango.demon.co.uk>,

Geoff Rimmer <s...@quango.demon.co.uk> wrote:
>Peter Shenkin wrote:
>> typedef float My_real_type;
>> My_real_type x;
>> scanf( "%f", &x );
>>
>> Now, later, you want to change the typedef to read as
>> follows:
>>
>> typedef double My_real_type;
>>
>> You still have to go through all the code and correct your
>> scanf's to agree with the new typedef. This cannot be
>> made automatic in C, unfortunately.
>
>Let the power of gcc 2.7.2 amaze you!

Well, you *still* have to go through all the code and
correct all your (printf, scanf, etc.) functions to agree
with the new typedef. Though it's nice to knew gcc can
tell you if you've blown it.

-P.

--
****** ********** In Memoriam, Bill Monroe, 1911 - 1996 ******************

Stephen Baynes

unread,
Sep 12, 1996, 3:00:00 AM9/12/96
to

Peter Shenkin (she...@still3.chem.columbia.edu) wrote:

: For instance, suppose you have code that looks like this:

: typedef float My_real_type;
: ...
: My_real_type x;


: scanf( "%f", &x );

: ...

: Now, later, you want to change the typedef to read as
: follows:

: typedef double My_real_type;

: You still have to go through all the code and correct your
: scanf's to agree with the new typedef. This cannot be
: made automatic in C, unfortunately.

If you route all your IO via an intermediate double value then you
have no problems and you code will be portable. [But it is more work,
especially for input.]

--
Stephen Baynes bay...@ukpsshp1.serigate.philips.nl
Philips Semiconductors Ltd
Southampton My views are my own.
United Kingdom
Are you using ISO8859-1? Do you see © as copyright, ÷ as division and ½ as 1/2?

Peter Holzer

unread,
Sep 12, 1996, 3:00:00 AM9/12/96
to

co...@mcnc.org (Carlie Coats) writes:

>But where is the guarantee that size_t fits into (unsigned long)??

>Suppose instead it requires (unsigned long long long) or some other
>such idiocy??

There is no type (unsigned long long long) in the standard. There
are only four unsigned integral types, unsigned long is the largest
of them and size_t must be one of them. So size_t does fit into unsigned
long.

Sorry, I don't have the standard at hand, so I can't cite chapter
and verse.

hp
--
_ | Peter J. Holzer | If I were God, or better yet
|_|_) | Sysadmin WSR | Linus, I would ...
| | | h...@wsr.ac.at | -- Bill Davidsen
__/ | http://wsrx.wsr.ac.at/~hjp/ | (davi...@tmr.com)

Kai Henningsen

unread,
Sep 14, 1996, 3:00:00 AM9/14/96
to

h...@wsr.ac.at (Peter Holzer) wrote on 12.09.96 in <hjp.84...@wsrdb.wsr.ac.at·2>:

> co...@mcnc.org (Carlie Coats) writes:
>
> >But where is the guarantee that size_t fits into (unsigned long)??
> >Suppose instead it requires (unsigned long long long) or some other
> >such idiocy??
>
> There is no type (unsigned long long long) in the standard. There
> are only four unsigned integral types, unsigned long is the largest
> of them and size_t must be one of them. So size_t does fit into unsigned
> long.
>
> Sorry, I don't have the standard at hand, so I can't cite chapter
> and verse.

At least the ANSI version seems to be *very* vague on this. I had trouble
even finding a statement that says long must be at least as large as int.
(It may be in there, but then it's well hidden.)

One thing I definitely didn't find was "size_t must be one of them".
Again, it *might* be possible to reason this out from the standard, but it
is by no means obvious. However, I couldn't find a statement saying that
you can't have numbers too large for (unsigned) long.

If someone else can't find an obvious statement of these, then that seems
to be a defect - the standard should be more explicit about this.

Kai
--
Internet: k...@khms.westfalen.de
Bang: major_backbone!khms.westfalen.de!kai
http://www.westfalen.de/private/khms/

Peter Seebach

unread,
Sep 14, 1996, 3:00:00 AM9/14/96
to

In article <6GpK7...@khms.westfalen.de>,

Kai Henningsen <k...@khms.westfalen.de> wrote:
>At least the ANSI version seems to be *very* vague on this. I had trouble
>even finding a statement that says long must be at least as large as int.
>(It may be in there, but then it's well hidden.)

It isn't, exactly. All we get is
6.1.2.5 Types
.... "signed char, short int, int, long int".

[pp. 4]
"In the list of signed integer types above, the range
of values of each type is a subrange of the values of the
next type in the list."

>One thing I definitely didn't find was "size_t must be one of them".

7.1.6 Common definitions


"size_t
which is the unsigned integral type of the result of the sizeof

operator; ..."

6.1.2.5
"For each of the signed integer types, there is a corresponding (but
different) unsigned integer type..."


So size_t must be one of the four unsigned types.

I agree, it should be more explicit anyway.

-s
--
Peter Seebach - se...@solon.com - Copyright 1996 - http://www.solon.com/~seebs
Unix/C Wizard - send mail for help, or send money for consulting!
The *other* C FAQ, the hacker FAQ, et al. See web page above.
Unsolicited email (junk mail and ads) is unwelcome, and will be billed for.

0 new messages