Reputation:
Consider the following code:
#include <stdio.h>
#include <inttypes.h>
void main(void)
{
int32_t a = 44;
fprintf(stdout, "%d\n", a);
fprintf(stdout, "%"PRId32"\n", a);
}
When is it better to use %d
and when would it be better to use "%"PRId32
? How do both of those format characters differ? Does this have something to do with how int32_t
is typedeffed on your hardware/machine?
Upvotes: 4
Views: 1565
Reputation: 569
The other 2 answers are both correct, but due to my career history I have some additional information to share.
With the advent of the C99 standard came <stdint.h>
which was a great gift for those developing C code which needed to be portable across different platforms. However, the printf
family format specifiers had already been in place before C99 and retained their meaning, and are dependent upon the size of an int
for each platform. If a development team used <stdint.h>
types to pass with printf
-family format specifiers, this causes the code to no longer be portable across different platforms. Let us take your code example above for illustration:
#include <stdio.h>
#include <inttypes.h>
void main(void)
{
int32_t a = 44;
fprintf(stdout, "%d\n", a); // Only safe on 32-bit platform.
fprintf(stdout, "%"PRId32"\n", a); // Safe on all platforms.
}
Let us also consider the microcontroller world, in which the same C code might need to be shared among different platforms (a.k.a. the size of the CPU's registers, which typically matches the size of the stack word -- which is where the printf
family of functions comes in). The printf
family of functions uses the chain of format specifiers to know where to read from the stack, and one of the format specifiers ("%n") accepts a pointer input, allowing the printf
functions to WRITE a value out to an integer variable, so it is imperative that the chain of format specifiers and the actual stack contents be in precise agreement, or else it can risk the printf
function reading from incorrect locations on the stack, or worse with the "%n" specifier, if a pointer is being read from the stack to which it will write, and it reads from an incorrect location on the stack, the probability that it will write to a dangerous (unintended) place in RAM is very high.
Consider these platforms:
int
has 16 bits [and same for register & stack word size])int
has 16 bits [and same for register & stack word size])int
has 32 bits [and same for register & stack word size])int
has 64 bits [and same for register & stack word size])Let us consider the first call to fprintf()
above: that will only be correct (and safe) on a 32-bit platform. If the code is used with an 8- or 16-bit platform, the format specifier will need to be changed to "%ld" to be correct (and thus safe). In other words, the code is not portable.
To solve this, C99 came with <inttypes.h>
which has printf
specifier-translation macros for the various int types that came with <stdint.h>
so that printf
family format specifier strings can be portable. (Each compiler knows the platform it will compile for, and the <inttypes.h>
and '<stdint.h>` files that ship with it are coded so as to be correct for the corresponding platform.)
How do you make it portable? Use specifiers as used in the 2nd call to fprintf()
above.
(Since PRId32
equates to a string constant [with quotation marks], the C compiler concatenates the strings together at compile time, thus, passing only one string constant to the fprintf()
function.)
Upvotes: 0
Reputation: 2813
Use %d
for int
and PRId32
for int32_t
.
Maybe on your platform int32_t
is just a typedef for int
but this is not true in general.
Using a wrong specifier invokes undefined behavior and should be avoided.
As pointed out by @EricPostpischil note that %d
is used inside a quoted format string while PRId32
is used outside. The reason for this is that PRId32
is a macro which expands to a string literal and is then concatenated.
Upvotes: 7
Reputation: 72463
The type int
is required to have at least 16 bits of value representation, although on most desktop computers and compilers it will have 32 bits. So int
might in general be the same as int16_t
, int32_t
, int64_t
, or none of the above.
Use "%d"
for variables of type int
, and use "%" PRId32
for variables of type int32_t
.
Upvotes: 4