I hate C printf format specifiers.  Alternatives? - Page 1
Forum section: electronics / general

author: Chris C
author_rank: Frequent Contributor
timestamp: August 27, 2015, 12:02:25 am
content: I just can't seem to remember what all these almost randomly chosen letters do. And after using a reference chart for the third time today, I wondered, am I alone? Or are there others like me? Maybe even someone who has designed an alternative, with user-friendliness in mind?I know it would be non-standard, but I could still use it for some things. Googling turned up some possibilities for C++, Haskell, and so on. But not plain C.

author: Macbeth
author_rank: Super Contributor
timestamp: August 27, 2015, 12:24:26 am
content: Seriously? Nothing could be simpler. More modern stuff uses regular expressions. Try that then go back to the simplicity of printf()

author: TopLoser
author_rank: Unknown
timestamp: August 27, 2015, 12:38:28 am
content: Nothing could be more simple! Give us an example of how you would do it better?!

author: rs20
author_rank: Super Contributor
timestamp: August 27, 2015, 12:43:52 am
content: Conciseness = user friendliness when it comes to coding. You could write one where you goprintFbyChris("I have %DECIMAL(figures=5,show_leading_zeros=true) bananas", ...)But I think even you would soon go back toprintf("I have %05d bananas", ...)

author: TopLoser
author_rank: Unknown
timestamp: August 27, 2015, 12:49:23 am
content: digits=5 surely?and so the confusion builds!

author: Zeyneb
author_rank: Regular Contributor
timestamp: August 27, 2015, 02:00:50 am
content: I do like the old fashioned printf type specifiers. In engineering education I first learned C and later C++. Then I was suggested to use cout for text output. With all that type safety propaganda. I wasn't able to see the benefit of that and simply sticked to printf and it's comrades in stdio.h. For me it was easy to verify the correctness of something that fits into a single line.I even do goto sometimes in C. No I don’t write spaghetti code. It is easier to follow a few goto’s than a complex while condition for me.

author: codeboy2k
author_rank: Super Contributor
timestamp: August 27, 2015, 02:27:26 am
content: I've used C for over 30 years now, I am quite used to the % format specifiers and I know the common ones like the back my hand, the more esoteric format specifiers I still have to look up. But once you know them they are quick and concise to write.However, I am still fond of the COBOL PICTURE clauses, even though I didn't have a COBOL careerFor those of us who remember Mark Williams COHERENT, there is a picture() function there, for C. In 2015, they open-sourced COHERENT and that particular picture() call is available in the libmisc source.picture(3101.1, "*$ZZZ,ZZZ.99", output_string) yields "$***3,101.10" inoutput_string.picture(5.1, "ZZ99", output_string) yields " 05" inoutput_string. (two spaces and 2 digits)http://www.nesssoftware.com/home/mwc/manpage.php?page=libmisc(scroll down to Pictures)The main page is herehttp://www.nesssoftware.com/home/mwc/COHERENT source is here :http://www.nesssoftware.com/home/mwc/source.php

author: SL4P
author_rank: Super Contributor
timestamp: August 27, 2015, 03:04:17 am
content: I like sprintf() for flexibility and the ability to arbitrarily concatenate formatted strings (without using strcat())If Chris is using Arduino - problem solved for simplicity, but not flexibility / performance.OMG - I almost forgot the COBOL picture statement... clumsy, but certainly readable)

author: Chris C
author_rank: Frequent Contributor
timestamp: August 27, 2015, 03:15:35 am
content: Heh. Maybe it is just me.C is NOT my primary language. So I see "d", and the first two thoughts that come to my mind is "double precision float". Or "decimal", which in the contexts I'm more used to, doesn't mean base 10 - it means a number stored much like a string, with no limit on the number of digits or precision. I know I can use "i" instead, and that makes more sense to me as an integer. But it seems like everyone else uses "d", so I feel obliged to use it as well. And then I don't mess with printf for a while, go back to old code and see "d", and get confused all over again. I try to figure it out without the reference chart, and it goes something like this:Hmm, "d" is an integer, right? But wait, "u" is an unsigned integer, so that would make a signed integer "i', and that makes "d"...double? Arg, gotta check that chart again...Seriously, WHY did they assign two letters to the same darn thing? I don't care what anyone says, this is NOT intuitive.I'm also trying to code for portability to other hardware. Currently in the middle of the second port, this time from 16 to 32 bit architecture. Had the foresight to write it from the start using types like int16_t where appropriate, which I typedef'ed to I16 for conciseness. So most of it's been super easy. But I'm now getting some stack issues using printf. In the process of looking into it, I find something that says in this scenario, I really should have been writing:printf("I have %05" PRIi16 " bananas", ...)Which is no longer concise, like 's original example. But at least it's totally unambiguous. And different enough that I no longer feel obliged to use "d", when I really want to use "i". Yet, if I want those bananas in hex, I have to do this:printf("I have %05" PRIx16 " bananas", ...)But what I'll end up doing is this:printf("I have %05" PRIi16x " bananas", ...)Remember I typedef'ed int16_t to I16? That means I'm going to instinctively want to put that "i" in there, right before the "16", every time. Which makes perfect sense, really, because IT IS STILL AN I16. That I'm asking for output in hex, has NOTHING to do with the input data type, and should NOT replace or require changes to that convention.So I can fix this with more defines. Give myself "PRIi16x", or more likely "priI16X" which fits in better with my existing I16 convention, and whatever else I want to do that is comfortable and intuitive. In fact, by adding a preprocessing wrapper around printf, I could make it accept any of these:printf("I have %05" priI16 priX " bananas", ...) // I16, uppercase hexprintf("I have %05" priX priI16 " bananas", ...) // I16, uppercase hexprintf("I have %05" priI16 prix " bananas", ...) // I16, lowercase hexprintf("I have %05" prix priI16 " bananas", ...) // I16, lowercase hexWhich is slightly less concise, but even more intuitive. Because then I don't even have to remember where in a naming convention the "x" is supposed to go. I will not be confused on whether the "x" replaces "I" or not, even if I have recently seen someone else using "PRIx16".And should I ever actually need a hex floating-point number (though I can't imagine why), I don't have to remember that somehow becomes "A". What is that "A" supposed to stand for anyway? Arcane? Who thought that was even useful? A signed hex integer is less weird, yet apparently impossible... Seriously, the more I look at all this, the more arbitrary it seems.Ok, rant mode off.My intent in posting this question was that before doing my own defines and whatnot, I just wanted to see if anyone else had come up with something similar, but possibly more elegant.

author: Chris C
author_rank: Frequent Contributor
timestamp: August 27, 2015, 03:17:57 am
content: Quote from: codeboy2k on August 27, 2015, 02:27:26 amThat looks similar to formatting functions I've used in other languages. I'll have to check that out, thanks.COBOL. My grandma coded in that, no kidding.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: August 27, 2015, 06:43:23 am
content: Quote from: Macbeth on August 27, 2015, 12:24:26 amUhh, regular expression are used for string parsing - not string formatting...I share Chris' sentiments. My day job makes me program in C# that uses a different set of placeholders. Result is the same, I also have to look these up when it gets more complex. So I guess, no matter what you think up - when you cannot remember the logic behind the placeholders it will always feel as a PitA.

author: helius
author_rank: Super Contributor
timestamp: August 27, 2015, 06:54:28 am
content: The big problem with C interfaces like printf() isn't that they are hard to remember, it's that they are completely untyped.

author: jwm_
author_rank: Frequent Contributor
timestamp: August 27, 2015, 07:04:38 am
content: Quote from: Chris C on August 27, 2015, 03:15:35 amI know this one, when reading text, %d is always base 10, while %i accepts any of the C standard number formats (like 0xff for 256, or 0177 for octal). This difference isn't important for printf because the default for %i is base 10, so it looks the same as %d, however for scanf there is a big difference. It would be weird for a specifier to work in scanf but not printf so printf accepts both even though they behave the same so you can reuse the same formatting strings to read/write the same data.And there is nothing wrong at all with using %i in printf for int. I use it exclusively, most modern programmers do I think for the reasons you state.

author: android
author_rank: Regular Contributor
timestamp: August 27, 2015, 08:08:16 am
content: Quote from: codeboy2k on August 27, 2015, 02:27:26 am...and, on IBM mainframes at least, the conversion is done with a single machine instruction.

author: tszaboo
author_rank: Super Contributor
timestamp: August 27, 2015, 09:35:04 am
content: Quote from: helius on August 27, 2015, 06:54:28 amYou sit in front of a computer when writing C code. It takes 4 seconds to type c lib printf into google, but you can print a C reference guide (good ones are 2-4 pages) and stick it on the wall if you are a programmer.I think it is the most convenient way of outputting a string. I find myself using it even if I'm programming in C++ or on Arduino for example. sprintf it to a buffer, serial.print the buffer, leave me alone with the made up bullshit. C string formatting is simple, elegant and it works regardless the architecture number of bits or platform.

author: rs20
author_rank: Super Contributor
timestamp: August 27, 2015, 09:43:49 am
content: Quote from: NANDBlog on August 27, 2015, 09:35:04 amThis doesn't seem to refute the claim that printf is completely untyped. Also, the OP has outlined the not-so elegant hacks you need for your printf to work "regardless the architecture number of bits or platform".

author: helius
author_rank: Super Contributor
timestamp: August 27, 2015, 09:48:49 am
content: QuoteThe problem with this specific strategy is that printf() commands are not type specifiers, they are format conversions. And if you understand the way that C passes arguments, you should know that "I16" is not the type of any actual argument to printf(). All arguments to a variadic function undergo the usual type conversions, which means that what printf() receives is simply an "int". It's seductive to think that you can fix C's unspecified-integer-width problems with type definitions and make everything a known number of bits, but this is not generally the case.QuoteMore programmers who are only as smart as googleQuoteExcellent, I'll make sure to give your products special attention when it comes to stack overflow exploits.QuoteYes, as long as you don't care whether overflow is detected or how many bits are actually given.

author: Jeroen3
author_rank: Super Contributor
timestamp: August 27, 2015, 10:41:01 am
content: This document explains the interface of the printf family.http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.htmlNotice that this is not a description of an implementation, but more the standard used. So results may vary depending on the laziness of the lib people.There is a lot of implicit type conversion going on, you should be able to make it more strict using the length modifiers. Still, no errors will be shown, it's C, not java.If you really don't like it, you can get angry for a week and create your own, it not impossible. But remember that the parameters occupy memory. So using %d if more efficient than using %int_16.thttp://chibios.sourceforge.net/html/group__chprintf.html

author: zapta
author_rank: Super Contributor
timestamp: August 27, 2015, 12:39:16 pm
content: Quote from: helius on August 27, 2015, 06:54:28 amSince compilers do verify the printf arguments if you use a literal format and complain if you don't. IIRC GCC has a pragma that allows to write functions of your own with printf like format and have the compiler verify it.EDIT: from GCC manual:format (archetype, string-index, first-to-check)The format attribute specifies that a function takes printf, scanf, strftime or strfmon style arguments which should be type-checked against a format string. For example, the declaration:extern intmy_printf (void *my_object, const char *my_format, ...)__attribute__ ((format (printf, 2, 3)));

author: ralphd
author_rank: Frequent Contributor
timestamp: August 27, 2015, 12:40:57 pm
content: Quote from: helius on August 27, 2015, 06:54:28 amSmart compilers can recognize the printf call and check the parameters.

author: legacy
author_rank: Super Contributor
timestamp: August 27, 2015, 02:02:41 pm
content: Quote from: helius on August 27, 2015, 06:54:28 amexactly, for that reason I prefer to create my collection of functions, one functions for every data typeuint32_t ---> put_uint32sint32_t ---> put_sint32char_t ---> put_char (which can be 8 or 16bit)string_t ---> put_stringthe code is also smaller than printf, and I do not need all the support for the stackADA works this way, and so my embedded C

author: Jeroen3
author_rank: Super Contributor
timestamp: August 27, 2015, 02:48:32 pm
content: Translations become more complicated though.With printf you can just swap the first arguments, with custom stuff and operator<< this becomes more work.

author: nctnico
author_rank: Super Contributor
timestamp: August 27, 2015, 02:59:33 pm
content: I agree. The elegance of printf is that you can mix fixed text and numbers. But nobody says you can't create your own printf. It isn't difficult to do that; there are many examples on how to create a function with a variable number of arguments. However.. some compilers (GCC for example) check the format specifier of printf against the type of the variable and emit a warning if there is a mismatch.

author: legacy
author_rank: Super Contributor
timestamp: August 27, 2015, 03:36:29 pm
content: Quote from: nctnico on August 27, 2015, 02:59:33 pmSierraC does not, that was the first reason why I have decided to created a dedicated function, one function for every data_type.ADA works exactly this way, so from my point of view I am simplifying my job (translating from ADA to C)

author: free_electron
author_rank: Super Contributor
timestamp: August 27, 2015, 04:02:56 pm
content: printf is unsafe ...

author: mikerj
author_rank: Super Contributor
timestamp: August 27, 2015, 04:57:58 pm
content: Quote from: free_electron on August 27, 2015, 04:02:56 pmprinttf is not type-safe, which is a very different thing to being fundamentally unsafe. It means the programmer must ensure he or she is using the function correctly rather than relying on run time error detection to save them from their incompetence.

author: Chris C
author_rank: Frequent Contributor
timestamp: August 27, 2015, 05:07:28 pm
content: Quote from: helius on August 27, 2015, 09:48:49 amThat's not exactly true. Say you have a two variables, both strongly typed. One int16_t, one int32_t.Print those variables on a 32-bit system. You can use "%d" for both. You're correct that the int16_t is converted to an int (int32_t) upon being passed to the varadic function.But on a 16-bit system, you have to use "%d" for the int16_t, and "%ld" for the int32_t.What would you call the printf() command "l" in that case, if not a type specifier?

author: Chris C
author_rank: Frequent Contributor
timestamp: August 27, 2015, 05:18:57 pm
content: Quote from: legacy on August 27, 2015, 03:33:19 pmNo need to make that from scratch. I have a "tiny printf" in my reference library, from Kustaa Nyholm, that looks like it would make an excellent starting point:http://www.sparetimelabs.com/tinyprintf/index.htmlNote that it could be made even tinier, especially if you're going to add support for more options. There's a "switch" statement there based on char values, and because those values are sparse (non-contiguous), it compiles to a series of individual "if" tests, rather than a jump table.You can instead put the chars in an array. Add a little code to try to look up the current char in the array. If found, use the array index to drive the switch statement. The cases will be contiguous, and will compile to a jump table.

author: ralphd
author_rank: Frequent Contributor
timestamp: August 27, 2015, 11:41:04 pm
content: Quote from: Chris C on August 27, 2015, 05:18:57 pmThere's also Elm Chan's xprintf.http://elm-chan.org/fsw/strf/xprintf.html

author: nctnico
author_rank: Super Contributor
timestamp: August 27, 2015, 11:53:46 pm
content: Quote from: ralphd on August 27, 2015, 11:41:04 pmHis reason for creating it is because the regular printf is sometimes too large. However creating functions with different names sucks because it makes code non-portable. If you use or create your own small/micro printf better call it printf. Since most C libraries export printf as weak the 'local' printf will take precedence over the library provided printf. Problem solved.

author: Kalvin
author_rank: Super Contributor
timestamp: August 28, 2015, 05:02:55 am
content: Quote from: legacy on August 27, 2015, 02:02:41 pmAnd it is very easy to provide also formatted versions of the put_XXX functions. The parameters might be the field width and the bitset of the flags (FMT_LEFT, FMT_RIGHT, FMT_ZEROPAD, FMT_LOCASE, FMT_UPCASE, etc.) passed either as two uint8s or one uint16 containing the width and the flags.

author: rs20
author_rank: Super Contributor
timestamp: August 28, 2015, 05:44:43 am
content: Quote from: legacy on August 27, 2015, 02:02:41 pmThis is my approach as well, but I didn't want to suggest such a manual approach. I find writing these five-line functions relaxing, but I was worried it was just me!The other great bonus with this approach is that if you use "fixed point integers"* (which are much faster than floats on integer-only hardware), you can write yourself a function that inserts a decimal point wherever you want. So it's just a little extra "decimal_points" argument which drops a decimal point at the right point in the string (which is being directly written to the UART of course, no actual string buffers here), and you get human-readable floating point numbers without a single byte of FPU-emulating code or printf.* i.e., an integer that you just have a comment next to saying "this is actually in millionthsHere's a reference example (completely untested, just dumped into the forum). A little bit recursion-heavy I grant you.Code:void printString(const char* s) {while (*s) printChar(*s++);}void printInt32(int32_t v, int8_t decimals) {if (v < 0) {printChar('-');printInt32(-v); // Bug for the reader to fix: will infinite loop if -2^31 is input.return;}int32_t div10 = v / 10;if (div10) {printInt32(div10, decimals - 1);if (decimals == 1) printChar('.');}printChar(v % 10 + '0');}void loop() {int32_t reading = read_from_ds18b20(...); // Read temperature from DS18B20+. LSB is 2^-4, i.e. 0.0625int32_t fixed_point = reading * 625; // Convert to fixed point with 4 decimal placesprintString("Temperature: ");printInt32(fixed_point, 4);printString(" degrees C\n");// Temperature: -2.4375 degrees C}

author: Chris C
author_rank: Frequent Contributor
timestamp: August 28, 2015, 08:57:13 pm
content: Thank you everyone for the ideas! I haven't decided which method I'm going to use yet, I have a few days before I need to.Just to see what would result, I spec'ed out another method from scratch. I'm curious how intuitive and readable others find it. If anyone cares to indulge me on that...The format specifier starts with '%' as usual, followed immediately by the fully spelled out variable type (or typedef). Then optional other stuff, which you get no hints on. Finally, it's terminated with a ';'. See how fast you pick up on it from these examples:Code:"%I16;"123 = "123"-123 = "-123""%UI32 h;"0x000000FF = "ff""%UI32 H 8;"0x000000FF = "000000FF""%UI8 b 8;"3 = "00000011""%Float;"0 = "0"1 = "1"1.23 = "1.23"1.237 = "1.237""%Float .2;"0 = "0.00"1 = "1.00"1.23 = "1.23"1.237 = "1.24""%Float .0-2;"0 = "0"1 = "1"1.23 = "1.23"1.237 = "1.24""%Float 3.3;"1 = "001.000"37.1827 = "037.183""%Float <12;"-1.23 = "-1.23 ""%Float , +s$ .2 >12;"-1234.56 = " -$1,234.56"1234.56 = " $1,234.56""%Float , +S$ .2 >12;"-1234.56 = " -$1,234.56"1234.56 = " +$1,234.56""%Float , +$S .2 >12;"-1234.56 = " $-1,234.56"1234.56 = " $+1,234.56""%Float .2 >12 +$S ,;"-1234.56 = " $-1,234.56"1234.56 = " $+1,234.56"

author: zapta
author_rank: Super Contributor
timestamp: August 30, 2015, 04:22:10 pm
content: Quote from: Chris C on August 28, 2015, 08:57:13 pmAbout the same complexity of the standard, if not more complex.Resistance is futile, join the Borg.

author: Chris C
author_rank: Frequent Contributor
timestamp: August 30, 2015, 11:40:24 pm
content: Quote from: zapta on August 30, 2015, 04:22:10 pmOh well. Thank you for the honest answer!

author: zapta
author_rank: Super Contributor
timestamp: August 31, 2015, 12:11:13 am
content: Is there an online printf calculator similar to the online regex calculators?

author: nctnico
author_rank: Super Contributor
timestamp: August 31, 2015, 01:03:30 am
content: Quote from: zapta on August 31, 2015, 12:11:13 amI'm not sure whether that is useful. In my experience the interpretation of certain format specifiers depends on the implementation

author: legacy
author_rank: Super Contributor
timestamp: September 01, 2015, 10:20:01 pm
content: printfand theUncontrolled Format String

author: nctnico
author_rank: Super Contributor
timestamp: September 01, 2015, 10:23:05 pm
content: Using non-constant strings in printf won't compile in a decent C compiler. GCC cannot even be coerced into doing something stupid like that. All in all not really an issue.

author: legacy
author_rank: Super Contributor
timestamp: September 01, 2015, 10:23:11 pm
content: a goodsolutionin C++

author: legacy
author_rank: Super Contributor
timestamp: September 01, 2015, 10:26:13 pm
content: Quote from: nctnico on September 01, 2015, 10:23:05 pmbut …SierraC will(it's a cross compiler, DOS-x86 to m68k-baremetalit was used byTexas Instrumentsfor their 68K pocket calculatorsTI89, TI92, etc ...)

author: westfw
author_rank: Super Contributor
timestamp: September 02, 2015, 12:35:31 am
content: I wrote some code for a Pascal compiler once, so that "Write" could generate formatted output.Ordinary Pascal apparently believing that such a thing was unnecessary, of course. I believe I used Fortran-style format strings. (Hey, it was ~1979, and making the output compatible with fortran READ statements was one of the big goals. You know, so that people could use Pascal for "Serious programming.")Some of the ugliness in printf() formats comes from being based on fortran formats, I think...Personally... If you use printf() often enough, you'll learn the format codes. The ones that you don't use often enough are OK to need to look up.QuoteI also once wrote a terminal emulator for the PC where I wanted to use the emulator itself for formatting help and menu screens and such, and I added "escape sequences" that would display internal program variables. Like "<ESC> V <string address>"; That never quite made it to "productization", and I didn't notice what a horrible source of bugs it was until years (decades?) later...

author: legacy
author_rank: Super Contributor
timestamp: September 02, 2015, 02:17:39 am
content: It's also interesting that inC++11you can use std::to_string:Code:std::string var = "sometext" + std::to_string(somevar) + "sometext" + std::to_string(somevar);A bit pedantic, but safe.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: September 02, 2015, 07:54:28 am
content: Quote from: legacy on September 02, 2015, 02:17:39 amBut not so optimal concerning memory allocations?

author: legacy
author_rank: Super Contributor
timestamp: September 02, 2015, 12:10:40 pm
content: Quote from: obiwanjacobi on September 02, 2015, 07:54:28 amunfortunately, it's the price to payI can't see better solutions in terms of safer solutions

author: codeboy2k
author_rank: Super Contributor
timestamp: September 02, 2015, 07:49:08 pm
content: For one or two ad hoc conversions to strings, then ok, go ahead and use std::to_string(). But for long formatted output, then stringstreams are also typesafe, cleaner looking, and more C++ ' ish if that's even a wordIf I saw someone writing C++ code using a series of chained std::to_string() like that I'd barf first, then take him outside for a talkNote that GNU libc++ delegates to snprintf() for all calls to std::to_string().There is also theC++ Format Library. Apparently it's heavily optimized for speed.Here's some examples from the documentation:Code:fmt::print("Hello, {}!", "world"); // uses Python-like format string syntaxstd::string s = fmt::FormatInt(42).str(); // convert to std::string// indexed and repeated argumentsstd::string s = fmt::format("{0}{1}{0}", "abra", "cad");// Result: s == "abracadabra"std::string s = fmt::format("{:*^30}", "centered"); // use '*' as a fill char// Result: s == "***********centered***********"std::string s = fmt::format("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);// Result: s == "int: 42; hex: 2a; oct: 52; bin: 101010"// with 0x or 0 or 0b as prefix:std::string s = fmt::format("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42);// Result: s == "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"A comparison of integer conversions using various formatting libraries is here:http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html

author: linux-works
author_rank: Super Contributor
timestamp: September 02, 2015, 08:15:02 pm
content: Quote from: zapta on August 31, 2015, 12:11:13 amits called python.lol

author: hamster_nz
author_rank: Super Contributor
timestamp: September 02, 2015, 09:24:22 pm
content: Quote from: nctnico on September 01, 2015, 10:23:05 pmAs far as I can tell, GCC doesn't care, even with all warnings on... What am I missing?Code:/tmp$ cat test.c#include <stdio.h>int main(int argc, char *argv[]){char format;sprintf(format,"%s","Format %s\r\n");printf(format,"Hello!");return 0;}/tmp$ gcc -Wall -o test test.c/tmp$ ./testFormat Hello!/tmp$

author: nctnico
author_rank: Super Contributor
timestamp: September 02, 2015, 10:37:34 pm
content: Good question. Last time I tried with GCC there was no way around it. Perhaps your array gets optimised into a constant? Try using argv as the format string.

author: Wim_L
author_rank: Regular Contributor
timestamp: September 02, 2015, 10:57:58 pm
content: There is no requirement that the string passed to printf or fprintf is a constant string literal.The type of the format string is specified as follows in the C99 standard: "const char * restrict format".The restrict can be disregarded here, it's a requirement that the format string won't be aliased with any other variable passed into the function. So, "const char * format". The const does NOT mean that this can only point to string constants! It can point to modifiable strings too. The const is simply a promise in the function declaration that the printf function will not modify the string through that pointer argument.Passing a string variable into printf as a format string is fine. GCC may warn about this, depending on its compilation flags (-Wformat-securityhttps://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html), but it's no error. It can certainly be dangerous if you're passing unchecked user input into it, that's something you definitely shouldn't do.

author: Jeroen3
author_rank: Super Contributor
timestamp: September 03, 2015, 05:34:56 am
content: This is because the location of const can cause confusion for many programmers.https://en.wikipedia.org/wiki/Const_(computer_programming)#Pointers_and_referencesPrintf doesn't care where the format string comes from. You can generate multiple tables, for each language, of format strings which you can select. And printf just delivers. You can even have the user enter one at runtime. It is unfortunate printf can not dereference pointers, if it could it would be another bit more helpful displaying templated layouts.

author: westfw
author_rank: Super Contributor
timestamp: September 03, 2015, 05:49:21 am
content: QuoteI was thinking of mentioning that things like the "picture" based formatting have to be pretty expensive at runtime. Something like ForTran can do a lot of the format processing at compile time because the feature is part of the language, but library-based functions as required by C are a lot harder to do. The current printf() seems like it's a pretty reasonable compromise (although, I think printf() can be a lot "heavier" than some of the simple versions would lead you to believe. I think I've seen printf implementations that end up calling malloc(), and running through the formatting twice for one reason or another.)

author: legacy
author_rank: Super Contributor
timestamp: September 04, 2015, 10:03:28 am
content: yet an other C++ alternative:C++format

author: legacy
author_rank: Super Contributor
timestamp: September 04, 2015, 10:05:50 am
content: the new strategy uses thevariadic templatemethod.

author: nctnico
author_rank: Super Contributor
timestamp: September 04, 2015, 02:12:43 pm
content: Quote from: Wim_L on September 02, 2015, 10:57:58 pmTrue but as I wrote before some compilers enforce that a format specifier is a string literal and not a pointer to a variable to prevent format string attacks.