c99 uint32_t (etc.) corresponding portable printf format specifiers?

D

David Mathog

c99 introduced (or at least standardized) uint32_t, uint64_t etc., and
that provides a way to write code
so that the size of the variables remains the same on platforms where
int, long, etc. can be different sizes. So far so good. However,
there do not seem to be any corresponding fprintf specifiers, just the
existing l, ll and u. and those do not have a fixed size. So in c99
how does one write this code fragment portably?


#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

uint32_t var=1;
fprintf(stdout,"%lu \n",var);

That would work on a 32 bit platform, but %lu could be 8 bytes on a 64
bit platform, rather than the intended 4 bytes.

Thanks,

David Mathog
 
B

Ben Pfaff

David Mathog said:
c99 introduced (or at least standardized) uint32_t, uint64_t etc., and
that provides a way to write code
so that the size of the variables remains the same on platforms where
int, long, etc. can be different sizes. So far so good. However,
there do not seem to be any corresponding fprintf specifiers, just the
existing l, ll and u. and those do not have a fixed size. So in c99
how does one write this code fragment portably?


#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>

uint32_t var=1;
fprintf(stdout,"%lu \n",var);

#include <inttypes.h>
fprintf(stdout, "%"PRIu32" \n", var);
 
D

David Mathog

#include <inttypes.h>
fprintf(stdout, "%"PRIu32" \n", var);

Thanks! Which man page, if any, includes this information? It isn't
in the fprintf page on my
Linux systems.

Thank you,

David Mathog
 
K

Keith Thompson

David Mathog said:
Thanks! Which man page, if any, includes this information? It isn't
in the fprintf page on my
Linux systems.

I don't know which man page it's in, if any, but it's documented
(defined, actually) in section 7.8 of the C99 standard. The latest
almost-official draft is at
http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

This won't tell you whether your implementation supports it; not
all do, and you might not get a warning for an unsupported format.

For simplicity, you might also consider converting to intmax_t or
uintmax_t (var was declared as uint32_t):

fprintf(stdout, "%ju\n", (uintmax_t)var);

Use "%ju" and cast to uintmax_t for unsigned variables, use "%jd" and
cast to intmax_t for signed variables. Personally, I find that easier
to remember than PRIu32 and friends. Widening to uintmax_t or intmax_t
might be more expensive, but that's hardly likely to be significant.
 
B

Ben Pfaff

Keith Thompson said:
For simplicity, you might also consider converting to intmax_t or
uintmax_t (var was declared as uint32_t):

fprintf(stdout, "%ju\n", (uintmax_t)var);

Use "%ju" and cast to uintmax_t for unsigned variables, use "%jd" and
cast to intmax_t for signed variables. Personally, I find that easier
to remember than PRIu32 and friends. Widening to uintmax_t or intmax_t
might be more expensive, but that's hardly likely to be significant.

One possible consideration is that it is fairly easy to #define
PRIu32, etc. on C89 systems that don't natively have <inttype.h>,
but it is harder to extend a system's printf implementation to
support the new C99 width modifiers such as 'j'.
 
E

Edward Rutherford

Ben said:
One possible consideration is that it is fairly easy to #define PRIu32,
etc. on C89 systems that don't natively have <inttype.h>, but it is
harder to extend a system's printf implementation to support the new C99
width modifiers such as 'j'.

Another consideration is that it's all very well saying that an
unnecessary type widening is "hardly likely to be significant", but this
sort of casual disregard for efficiency has a tendency to snowball, so
that in the end a whole lot of things that individually are "hardly
likely to be significant" accumulate into major bloat and slowdown.
 
D

David Mathog

For simplicity, you might also consider converting to intmax_t or
uintmax_t (var was declared as uint32_t):

    fprintf(stdout, "%ju\n", (uintmax_t)var);

Use "%ju" and cast to uintmax_t for unsigned variables, use "%jd" and
cast to intmax_t for signed variables.

The variables correspond to fixed width fields in binary files. I'm
not entirely clear
on what uintmax_t is, but my first impression was that it was "the
biggest int that this
platform can handle". So on a 64 bit platform wouldn't that be a 64
bit int? Which is not
what is needed when the file has 32 bit fields. Well, I guess it
would work for the printf,
but there would be problems trying to stuff data back into the 32 bit
field from the 64 bit int.

Thanks,

David Mathog
 
K

Keith Thompson

David Mathog said:
The variables correspond to fixed width fields in binary files. I'm
not entirely clear on what uintmax_t is, but my first impression was
that it was "the biggest int that this platform can handle".

No, it's the biggest *unsigned integer type* supported by the C
implementation. Remember that "int" is just one of several predefined
integer types; it's not just a shorter way of saying "integer".

Specifically, quoting C99 7.18.1.5:

The following type designates a signed integer type capable of
representing any value of any signed integer type:

intmax_t

The following type designates an unsigned integer type capable
of representing any value of any unsigned integer type:

uintmax_t

These types are required.
So on a
64 bit platform wouldn't that be a 64 bit int?

It would probably be a 64-bit *integer*, though it's possible that a C
implementation on a 64-bit platform might also support 128-bit integers.
Which is not what is
needed when the file has 32 bit fields. Well, I guess it would work
for the printf, but there would be problems trying to stuff data back
into the 32 bit field from the 64 bit int.

No, you don't *need* to use 64 bits. The point is simply that
converting printf arguments to int64_t or uint64_t means there's less
stuff to keep track of; you don't have to remember that the conversion
macros for uint32_t, uint_fast32_t, and uint least32_t are PRIu32,
PRIuLEAST32, and PRIuFAST32, respectively. And if you change the
definition of your variable from uint32_t to uint64_t, the printf will
still work correctly. Converting from 32 bits to 64 probably imposes
some runtime overhead, but it's probably swamped by the overhead
of printf() parsing the format string and printing the output.
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top