If I want a program to have multiple text output formats, I could do something like this:
const char *fmtDefault = "%u x %s ($%.2f each)\n";
const char *fmtMultiLine = "Qty: %3u\nItem: %s\nPrice per item: $%.2f\n\n";
const char *fmtCSV = "%u,%s,%.2f\n";
const char *fmt;
switch (which_format) {
case 1: fmt = fmtMultiLine; break;
case 2: fmt = fmtCSV; break;
default: fmt = fmtDefault;
}
printf(fmt, quantity, item_description, price);
Since the price is specified last, I could also add one that doesn't list prices:
const char *fmtNoPrices = "%u x %s\n";
But what if I want to omit the quantity instead? If I did this:
const char *fmtNoQuantity = "The price of %s is $%.2f each.\n";
then undefined behavior (most likely a segfault) will occur rather than what I want. This is because it will treat the first parameter as a pointer to a string, even though it's actually an unsigned int. This unsigned int will most likely point to something other than valid string data, or (much more likely, especially if you're not buying hundreds of millions of the same item) an invalid memory location, resulting in a segmentation fault.
What I want to know is if there's a code I can put somewhere (%Z
in this example) to tell it to skip that parameter, like this:
const char *fmtNoQuantity = "%ZThe price of %s is $%.2f each.";
For %s
values, there is a “null” printf() code: %.0s
.
You could reach a general solution via:
When possible, re-arrange so that non-%s
values are last, and then under specify the format string.
My favorite for you is to have 3 separate printf() calls, one for each value using its own format. When the value is not needed, simply supply a format string with no specifiers.
const char * Format1q = "";
const char * Format1id = "The price of %s";
const char * Format1p = " is $%.2f each.\n";
...
printf(Format1q, quantity);
printf(Format1id, item_description);
printf(Format1p, price);
Weird solutions:
For other values that are the same size you could attempt the Undefined Behavior of also using %.0s
. (worked with some samples in gcc 4.5.3, who knows in other compilers or the future.)
For other values that are the N x the same size as a pointer size you could attempt the Undefined Behavior of also using %.0s
N times. (worked with some samples in gcc 4.5.3, who knows in other compilers or the future.)
I actually figured this out on my own while looking something up for my question. You can prepend a parameter number, followed by a $
to the format code, after the %
. So it would be like this:
const char *fmtNoQuantity = "The price of %2$s is $%3$.2f each.";
That is, the string would use the 2nd parameter, and the float would use the 3rd parameter. Note, however, that this is a POSIX extension, not a standard feature of C.
A better method would probably be to define a custom printing function. Something like this:
typedef enum {fmtDefault, fmtMultiLine, fmtCSV, fmtNoPrices, fmtNoQuantity} fmt_id;
void print_record(fmt_id fmt, unsigned int qty, const char *item, float price)
{
switch (fmt) {
case fmtMultiLine:
printf("Qty: %3u\n", qty);
printf("Item: %s\n", item);
printf("Price per item: $%.2f\n\n", price);
break;
case fmtCSV:
printf("%u,%s,%.2f\n", qty, item, price);
break;
case fmtNoPrices:
printf("%u x %s\n", qty, item);
break;
case fmtNoQuantity:
printf("The price of %s is $%.2f each.\n", item, price);
break;
default:
printf("%u x %s ($%.2f each)\n", qty, item, price);
break;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With