The format string you pass to printf
is a mixture of ordinary characters and format specifiers. The ordinary characters print as themselves, and the format specifiers cause one of the extra arguments to be converted and printed. But the type of each extra argument must match the type expected by the format specifiers, more or less exactly.
We can tell from the warning message that pid
is an int
. So the correct format specifier is %d
.
The specifier %lu
would have been correct if pid
had type unsigned long int
.
Format specifiers are sort of their own little miniature programming language. The basic format specifier for type unsigned int
is %u
, and you can modify it to print unsigned long int
instead with the l
(letter ell) modifier: %lu
.
But when you write %lun
, the n
wasn't actually part of any format specifier, so it printed as itself.
(Also, you got lucky: despite the mismatch between pid
's type and the format specifier %lu
, you got a sensible value printed anyway.)
Usually, getting the arguments and the format specifiers to line up is easy: int
for %d
, unsigned int
for %u
or %x
, long int
for %ld
, float
or double
for %f
, etc. But what's the right specifier to use for pid
, which has type pid_t
? Today, on your computer, it looks like pid_t
is an int
, so %d
would be correct, but what if, on some other computer, it has a different type? How can you write one piece of code that will work correctly on any computer? One way is to pick a type that's probably right, and use the specifier for that type, and then use an explicit cast to convert your value to the type you picked. Like this:
printf("pid: %d\n", (int)pid);
Or like this:
printf("pid: %lu\n", (unsigned long int)pid);
If the cast isn't necessary (if the format specifier you picked is already correct for the type of pid
on your computer), the cast won't hurt.
Finally, congratulations on using a compiler that actually gave you the warning message:
warning: format specifies type 'unsigned long' but the argument has type 'pid_t' (aka 'int')
Too many beginning programmers are stuck using older compilers that don't print warnings like these, and that obviously makes it much more difficult to track down problems caused by mismatched format specifiers! (Your compiler was particularly helpful in that it gave you both the apparent type of pid
, namely pid_t
, and also the actual underlying type, int
.)