printf formats for size_t?

D

David Mathog

size_t varies from system to system. This occasionally leads to
coding issues such as:

(void) sprintf(msg,"length of buffer: %d",strlen(msg));

which worked fine on a 32 linux but triggered errors with gcc
on an X86_64 system. (Ok, it should probably have been a %u rather
than a %d, but since msg was always going to be short it didn't
affect the program's execution.)

The gcc printf man page indicates that "%zu", "%zx", etc. tell the
compiler that the variable has type size_t, whatever size_t happens to
be. Is "z" part of the C standard or is it a gcc extension? If the
former, at what point did "z" become part of C?


Thanks,

David Mathog
(e-mail address removed)
 
J

Jens.Toerring

David Mathog said:
size_t varies from system to system. This occasionally leads to
coding issues such as:
(void) sprintf(msg,"length of buffer: %d",strlen(msg));
which worked fine on a 32 linux but triggered errors with gcc
on an X86_64 system. (Ok, it should probably have been a %u rather
than a %d, but since msg was always going to be short it didn't
affect the program's execution.)

Even better cast the size_t value to unsigned long and print with
"%lu", so it works also if size_t is larger than int.
The gcc printf man page indicates that "%zu", "%zx", etc. tell the
compiler that the variable has type size_t, whatever size_t happens to
be. Is "z" part of the C standard or is it a gcc extension? If the
former, at what point did "z" become part of C?

With the C99 standard. It says:

'z' Specifies that a following 'd', 'i', 'o', 'u', 'x', or
'X' conversion specifier applies to a 'size_t' or the
corresponding signed integer type argument; or that a
following 'n' conversion specifier applies to a pointer
to a signed integer type corresponding to 'size'_t argu-
ment.
Regards, Jens
 
K

Keith Thompson

David Mathog said:
size_t varies from system to system. This occasionally leads to
coding issues such as:

(void) sprintf(msg,"length of buffer: %d",strlen(msg));

which worked fine on a 32 linux but triggered errors with gcc
on an X86_64 system. (Ok, it should probably have been a %u rather
than a %d, but since msg was always going to be short it didn't
affect the program's execution.)

The gcc printf man page indicates that "%zu", "%zx", etc. tell the
compiler that the variable has type size_t, whatever size_t happens to
be. Is "z" part of the C standard or is it a gcc extension? If the
former, at what point did "z" become part of C?

As Jens Toerring pointed out, the "%zu" format is new in C99. That
means that some systems don't yet support it. (Incidentally, there is
no "gcc printf man page". printf is part of the runtime library; gcc
is just the compiler. gcc typically uses the native runtime library
on a given system, so having a current version of gcc is no guarantee
that printf() supports "%zu".)

For C90, the best way to print a size_t value is to use "%lu" and cast
the value to unsigned long. This will *almost* always work in C99 as
well. The only case where it won't is when size_t is bigger than
unsigned long (I don't know of any platforms where this is the case)
*and* the specific value you're printing exceeds ULONG_MAX.

For complete portability, you can query the __STDC_VERSION__ macro
(first check whether it's defined, then check the value) to determine
whether the implementation supports C99. On the other hand, just
because the compiler defines __STDC_VERSION__ as 199901L, that doesn't
necessarily guarantee that runtime library is also conforming. It
should, and it's arguably a bug if it doesn't, but it's a bug I've
seen on at least one real system.
 
C

CBFalconer

Even better cast the size_t value to unsigned long and print with
"%lu", so it works also if size_t is larger than int.


With the C99 standard. It says:

'z' Specifies that a following 'd', 'i', 'o', 'u', 'x', or
'X' conversion specifier applies to a 'size_t' or the
corresponding signed integer type argument; or that a
following 'n' conversion specifier applies to a pointer
to a signed integer type corresponding to 'size'_t argu-
ment.

However this is actually implemented in the library, which supplies
a large interpreter for the printf formatting system [1]. This
means that you can have a compiler (such as gcc executed with
-std=C99) that accepts the code, and have things fail at run time.
The libraries are usually supplied with the operating system. Be
warned.

[1] This large interpreter is the reason to avoid printf and
friends when compact code is required. Specialized routines
outputting via putc or fputs can save a good deal of code space,
especially in embedded systems.

--
Some informative links:
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html
 
T

tedu

Keith said:
For C90, the best way to print a size_t value is to use "%lu" and cast
the value to unsigned long. This will *almost* always work in C99 as
well. The only case where it won't is when size_t is bigger than
unsigned long (I don't know of any platforms where this is the case)
*and* the specific value you're printing exceeds ULONG_MAX.

64 bit Windows. long is still 32 bits. see
http://www.microsoft.com/whdc/driver/kernel/64bit_chklist.mspx for more
fun.
 
C

Clark S. Cox III

As Jens Toerring pointed out, the "%zu" format is new in C99. That
means that some systems don't yet support it. (Incidentally, there is
no "gcc printf man page". printf is part of the runtime library; gcc
is just the compiler. gcc typically uses the native runtime library
on a given system, so having a current version of gcc is no guarantee
that printf() supports "%zu".)

For C90, the best way to print a size_t value is to use "%lu" and cast
the value to unsigned long. This will *almost* always work in C99 as
well. The only case where it won't is when size_t is bigger than
unsigned long (I don't know of any platforms where this is the case)

Just an FYI, for better or worse, it's about to get a lot more common;
64-bit Windows uses the LLP64 convention. i.e.:

int: 32-bits
long: 32-bits
long long: 64-bits
size_t: 64-bits
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top