portable printf of different size types

D

dacium

What is the easiest way to use printf when you are writing portable
code for systems that have different ranges on integer types etc?

For example you might have to do:
unsigned long foo=70000; printf("%lu",foo); //on one system
unsigned int foo=70000; printf("%u",foo); //and that on another system

I wrote a wrapper around printf that adds a format character to
specify bit length data types:
port_printf("%32t %64t %16t %8t",foo,foo2 etc which gets translated to
the right type based on limits.h, but this has problems because I can
never just use a const format string, i have to copy the format string
and pass a new one to printf etc.

Are there any less painful ways?
 
K

Keith Thompson

What is the easiest way to use printf when you are writing portable
code for systems that have different ranges on integer types etc?

For example you might have to do:
unsigned long foo=70000; printf("%lu",foo); //on one system
unsigned int foo=70000; printf("%u",foo); //and that on another system

I wrote a wrapper around printf that adds a format character to
specify bit length data types:
port_printf("%32t %64t %16t %8t",foo,foo2 etc which gets translated to
the right type based on limits.h, but this has problems because I can
never just use a const format string, i have to copy the format string
and pass a new one to printf etc.

Are there any less painful ways?

Use the widest type and convert. For example, assuming a C90
implementation:

printf("%lu", (unsigned long)foo);

Or, given C99:

printf("%ju", (intmax_t)foo);

Note that you have to know whether foo's type is signed or unsigned.

Or you could just declare foo as unsigned long unconditionally and use
"%lu". This will waste some space on platforms where unsigned int is
big enough; you'll have to decide whether the programming convenience
is worth the cost.
 
B

Ben Pfaff

What is the easiest way to use printf when you are writing portable
code for systems that have different ranges on integer types etc?

For example you might have to do:
unsigned long foo=70000; printf("%lu",foo); //on one system
unsigned int foo=70000; printf("%u",foo); //and that on another system

This does not make any sense. Regardless of the system, %lu is
always correct for unsigned long, and %u is always correct for
unsigned int.

I suspect that you really have a typedef or macro that expands to
something system-specific, and you need to be able to print a
value of that type. size_t is a standard example of such a
typedef.

There are two common approaches to solving this problem. One is
to cast a value of the typedef to a type that is guaranteed to be
big enough. For example, if the type in question might be
unsigned int or unsigned long, you could do this:
printf("%lu", (unsigned long int) foo);

The other common approach is to accompany the typedef by a macro
that expands to the correct printf specifier, e.g.
#define PRI_TYPE "lu" /* assuming the type is unsigned long */
...
printf("%"PRI_TYPE, foo);
I wrote a wrapper around printf that adds a format character to
specify bit length data types:
port_printf("%32t %64t %16t %8t",foo,foo2 etc which gets translated to
the right type based on limits.h, but this has problems because I can
never just use a const format string, i have to copy the format string
and pass a new one to printf etc.

C99 adds new headers <stdint.h> and <inttypes.h> that provide
intN_t, for N = 8, 16, 32, and 64 (on systems that support
them), and corresponding PRIdN, PRIuN, PRIxN, etc. macros of the
form described above. You can find out more about them on the
web so I won't go into details.
 
J

James Kuyper

What is the easiest way to use printf when you are writing portable
code for systems that have different ranges on integer types etc?

For example you might have to do:
unsigned long foo=70000; printf("%lu",foo); //on one system
unsigned int foo=70000; printf("%u",foo); //and that on another system

I wrote a wrapper around printf that adds a format character to
specify bit length data types:
port_printf("%32t %64t %16t %8t",foo,foo2 etc which gets translated to
the right type based on limits.h, but this has problems because I can
never just use a const format string, i have to copy the format string
and pass a new one to printf etc.

Are there any less painful ways?

You've duplicated, with different syntax, some of the functionality that
was added to the C standard library in C99.

Use <inttypes.h>, if you can. uint_least32_t will be able to represent
70000 on any implementations supporting at least that part of C99. So
will uint_fast32_t. If a macro named UINT32_MAX is #defined by
<stdint.h>, then uint32_t will exist, and it can hold 70000 as well. Use
whichever of those three types is most appropriate to the way you'll be
using foo, and then print it with the corresponding PRI* macro from
<inttypes.h>.

However, the PRI* macros are clumsy. The simpler, more elegant solution
is simply to use 'unsigned long' for foo, even on systems where 'long'
is too big. Then you can always simply use %lu. This approach has the
advantage of working even with C90 compilers.
 
C

CBFalconer

What is the easiest way to use printf when you are writing portable
code for systems that have different ranges on integer types etc?

Try just: printf("%ld", (long) foo);

Whatever type foo actually is, it will be converted to a long and
printed. Don't forget to add a fflush or a '\n' to that output.
 
A

Antoninus Twink

Try just: printf("%ld", (long) foo);

Of course! That will work wonderfully well if foo is an unsigned long!
More great advice from CBF! And let's not speak about long longs on
32-bit systems!
 
A

Antoninus Twink

I'll bite. What's wrong w/ (long long) on 32-bit systems?

Since long long is guaranteed to be at least 64 bits, if long is 32 bits
then CBF's claimed magic formula

to print any integer type will (I think) invoke "undefined behavior"
when foo is a long long - or in practise, it will just give the wrong
answer. (Unlike with unsigned integer-types, a signed overflow is UB
isn't it?)
 
G

Guest

Since long long is guaranteed to be at least 64 bits, if long is 32 bits
then CBF's claimed magic formula

Oh. The exclamation made me think you had some other point. (long) on Win64
is still 32-bits, so the implied dichotomy isn't true, either. Maybe that's
why I misinterpreted ;)
to print any integer type will (I think) invoke "undefined behavior"
when foo is a long long - or in practise, it will just give the wrong
answer. (Unlike with unsigned integer-types, a signed overflow is UB
isn't it?)

I'm inclined to say it's unspecified, but my copy of the [C99] standard is
in another hemisphere. Probably I'm confusing it w/ the opposite conversion.
I try to stay away from signed integers like the plague anyhow; 'tis easier
than remembering the rules, and coding around them.

I came to exactly the opposite conclusion!
Stay away from unisgned integers. Apart from using
unsigned char for octets
 
C

CBFalconer

.... snip ...
I'm inclined to say it's unspecified, but my copy of the [C99]
standard is in another hemisphere. Probably I'm confusing it
w/ the opposite conversion. I try to stay away from signed
integers like the plague anyhow; 'tis easier than remembering
the rules, and coding around them.

I came to exactly the opposite conclusion! Stay away from
unisgned integers. Apart from using unsigned char for octets

You should consider the requirements. For example, arithmetic on
unsigned integral quantities is always safe, and you can detect
incipient overflows if necessary. Since overflow in signed
integers invokes undefined behaviour, you never really know what
can happen. Detecting incipient overflow is somewhat tricker also.
 
B

Ben Pfaff

CBFalconer said:
For example, arithmetic on unsigned integral quantities is
always safe, and you can detect incipient overflows if
necessary.

Unsigned integer arithmetic has well-defined results in cases
where signed integer arithmetic overflows, but saying that it is
"always safe" is an exaggeration. Division by zero still yields
undefined behavior as an unsigned integer, as does attempting to
shift an unsigned integer left or right a negative number of
places, and so on.
 

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,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top