I am continuing with printf as a follow up to Part 1.
Also, check out our tutorials on scanf and sscanf!
This tutorial would explore some thorough usage of printf and will talk about some scenarios that are not very frequently seen or encountered.
However, apart from merely trying to show “WOW! I didn’t know this can be done with printf”, I would try to cover all possible usages that are applicable in writing practical software applications.
One fundamental but common ignored aspect of printf is the return value. It returns the number of characters written.
printf("%d\n", printf("")); // %d is used to print a signed integer
would print 0 where as
would print 'Hi' (quotes only for clarity) on one line followed by a 3 on the next line. Note that ‘\n’ is also counted as a character written but the string terminator ‘\0’ in “Hi” is ignored since it is not printed.
Now applying this approach to variables, there is an important point to remember. Say you have a string containing a %d (the second one in below e.g.) used by printf. Now this %d represents an integer a whose value is 124. Because this is converted to a string and printed on the screen, it would return the count of characters i.e. number of digits in a (which are 3) plus 1 for the newline character (‘\n’). Hence the below code should print 124 on first line followed by 4 on the next line. If we had a six digit number printed, function would return 6 plus 1 for the newline.
int a = 124; printf("%d\n", printf("%d\n", a));
This is a useful aspect of the function which can be of help for error checking. At the very least it can provide insight to code about what was printed.
Whenever you need to print an address of a variable (a pointer precisely), use %p
int var = 12; printf("%p\n", &var); // printed 0044FA98 on my windows 7 64 bit machine
It is important to understand that pointer is an address and can only be used correctly when it actually points to a valid memory location.
Doing a printf on int *p; can have undefined result. Some compilers would complain an uninitialized pointer, where as others might crash.
Similar to how we can specify a flag such as ‘-’ or ‘+’ for left justification in between “%” and “d”, we can also specify some more characters such as ‘#’ or ‘0’ i.e.
int v = 10; printf("%#x\n",v); // would print 0xa
Note the prepended 0 in the beginning. Without the # it would have simply printed ‘a’. ‘#’ prepends 0x to hex or 0 only to octal value. Similarly a 0 can be used in place of #. It’s implication is when width of a field is specified already using %[width] e.g. %7 (7 characters wide field), then a prefixing ‘0’ would fill the empty spaces with 0’s.
The complete format of printf string is
Where specifier is something like d, f or u. Flags is one of +,-,# etc. width is an integer width of the field, precision is the number of digits to be printed after the decimal and length is the specifier which qualifies the length of a type precisely.
An example of usage of length field is
__int64 var = 232132112112; // on windows long long var = 232132112112; // on linux
To correctly print the above we would use a %d with ll prefix for long long. This ‘ll’ specifies the length of integer.
Now moving towards a few insane examples of printf
What do you think will be the output of the following?
The weird part of course is that format string contains two % arguments but no specifier and no follow up arguments. Yet it compiles and does produce some predictable results.
The first argument after % is taken as width of field i.e. 3 and hence is not printed. However, it expects a specifier latter instead of which it finds another %. Standard says % followed by % prints it to stdout. Hence you should see % printed first. Now because effect of % is lost, so 2 is treated and printed as a normal number.
Therefore, above code fragment prints %2 on the screen.
Another interesting example
A double by default with %f should print six places after the decimal. However, specifying precision with a ‘.’ followed by integer value in between % and f is something already known.
The additional part here is that you can put in a * in place of that integer value and put a variable after the formatted string. * indicates that the value should be picked up from parameters. Hence the constant 2 in the above example indicates the precision of 2 places after the decimal. Once can easily replace this 2 with a variable. Note that this variable should be placed before the actual double variable i.e. fvar in this case.
Don't forget to read up on our tutorial on sscanf!
Edited by Roger, 19 February 2013 - 02:39 PM.