64 bit portability, size_t, and printf format strings

D

dank

http://msdn2.microsoft.com/en-us/library/tcxf1dw6.aspx
describes the integer format modifiers accepted by Microsoft's printf.

http://www.gnu.org/software/libc/manual/html_node/Integer-Conversions.html
describes the integer format modifiers accepted by glibc's printf.

They differ (no big surprise), but the difference that's
bugging me today is how size_t integers are handled.
It looks like one has to do %Id (that's a capital i) in windows, and
%zd everywhere else.
This didn't use to matter much, but now that 64 bit portability is
becoming important, source code that used to happily print size_t's
with %d
is hurting. The way I've been dealing with it is to imitate
<inttypes.h>
and define a macro holding the format char for size_t, say

#ifdef MSVC
#define PRIdS "Id"
#else
#define PRIdS "zd"
#endif
....
printf("sizeof(foo_t) is %" PRIdS ".\n", sizeof(foo_t));

but that's awful ugly. I don't suppose we could convince Microsoft to
push out an updated msvcrt.dll that supported the 'z' format modifier
as an alternative to their 'I' modifier?
- Dan
 
E

Eric Sosman

dank wrote On 06/29/06 13:12,:
http://msdn2.microsoft.com/en-us/library/tcxf1dw6.aspx
describes the integer format modifiers accepted by Microsoft's printf.

http://www.gnu.org/software/libc/manual/html_node/Integer-Conversions.html
describes the integer format modifiers accepted by glibc's printf.
[...]

You could dodge the issue by using a C90 work-around:

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

.... on the assumption that no legitimate object will be
larger than ULONG_MAX bytes.
 
J

Jack Klein

http://msdn2.microsoft.com/en-us/library/tcxf1dw6.aspx
describes the integer format modifiers accepted by Microsoft's printf.

http://www.gnu.org/software/libc/manual/html_node/Integer-Conversions.html
describes the integer format modifiers accepted by glibc's printf.

They differ (no big surprise), but the difference that's
bugging me today is how size_t integers are handled.
It looks like one has to do %Id (that's a capital i) in windows, and
%zd everywhere else.
This didn't use to matter much, but now that 64 bit portability is
becoming important, source code that used to happily print size_t's
with %d
is hurting. The way I've been dealing with it is to imitate
<inttypes.h>
and define a macro holding the format char for size_t, say

#ifdef MSVC
#define PRIdS "Id"
#else
#define PRIdS "zd"
#endif
...
printf("sizeof(foo_t) is %" PRIdS ".\n", sizeof(foo_t));

but that's awful ugly. I don't suppose we could convince Microsoft to
push out an updated msvcrt.dll that supported the 'z' format modifier
as an alternative to their 'I' modifier?
- Dan

The EU has been trying to "convince" Microsoft to comply with the
terms of an antitrust settlement for two years.

Feel free to try to "convince" them to add something to their
implementations merely because it conforms to a non Microsoft specific
standard.
 
S

Skarmander

dank said:
http://msdn2.microsoft.com/en-us/library/tcxf1dw6.aspx
describes the integer format modifiers accepted by Microsoft's printf.

http://www.gnu.org/software/libc/manual/html_node/Integer-Conversions.html
describes the integer format modifiers accepted by glibc's printf.

They differ (no big surprise), but the difference that's
bugging me today is how size_t integers are handled.
It looks like one has to do %Id (that's a capital i) in windows, and
%zd everywhere else.
This didn't use to matter much, but now that 64 bit portability is
becoming important, source code that used to happily print size_t's
with %d
is hurting.

That's because you shouldn't print size_t's with %d; assuming that a size_t
will convert to an int "happily" is just silly. At the very least print them
as unsigned. The standard workaround for not having a size_t format
specifier (a great many systems don't, and C89 itself didn't) is to convert
the size_t to an unsigned long and print with %lu. Although this can still
be wrong, it's far less likely to be wrong than %d.
The way I've been dealing with it is to imitate <inttypes.h> and define a
macro holding the format char for size_t, say
#ifdef MSVC
#define PRIdS "Id"
#else
#define PRIdS "zd"
#endif
...

Not bad, but I'd make it %Id and %zd (no need to split them there just
because % is a common character) and make %lu the default, not %zd. That
will only work on systems with a C99-ready C library. You could also add a
check for long long support to use %llu. Not all systems support that
either, but it's more common than %zd support.

To make %lu and %llu work, of course, you need some typedefs for the type
used to print size_t's, so you get something like

printf("sizeof(foo_t) is " SIZE_T_FMT_SPEC ".\n", (size_t_print_type)
(sizeof(foo_t)));
printf("sizeof(foo_t) is %" PRIdS ".\n", sizeof(foo_t));

but that's awful ugly.

The least-effort solution that will get things to work everywhere is allowed
to be ugly. You can alternatively champion the cause of C99 support, but
while worthy, it's not as likely to be successful in the short run.
I don't suppose we could convince Microsoft to push out an updated
msvcrt.dll that supported the 'z' format modifier as an alternative to
their 'I' modifier?

Don't hold your breath. C libraries aren't updated that often. Microsoft's
is no exception. Even *if* Microsoft updated the CRT, it'll be years before
everyone has the updated version. (I do mean years, not some arbitrarily
long time.) The situation is somewhat less dire on Unix systems, but don't
kid yourself into thinking that there's universal support there today.

S.
 
S

Skarmander

Skarmander said:
dank wrote:

Not bad, but I'd make it %Id and %zd (no need to split them there just
because % is a common character)

Well, no, but you may want to add flags and field width and whatnot, so
better to keep the % out of there. Although I don't imagine you'd do much
alternate formatting with a size_t, there's no reason to forbid it.

S.
 
S

Simon Biber

dank said:
http://msdn2.microsoft.com/en-us/library/tcxf1dw6.aspx
describes the integer format modifiers accepted by Microsoft's printf.

http://www.gnu.org/software/libc/manual/html_node/Integer-Conversions.html
describes the integer format modifiers accepted by glibc's printf.

They differ (no big surprise), but the difference that's
bugging me today is how size_t integers are handled.
It looks like one has to do %Id (that's a capital i) in windows, and
%zd everywhere else.

No. It should be %Iu on Windows and %zu everywhere else. Remember that
size_t is an unsigned integer type!
This didn't use to matter much, but now that 64 bit portability is
becoming important, source code that used to happily print size_t's
with %d
is hurting.

Yes. However on all the 64-bit compilers I've used so far, 'unsigned
long' moved to 64 bits, so you could still use %lu and cast the size_t
value to unsigned long.
 

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

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,815
Latest member
treekmostly22

Latest Threads

Top