Author Topic: I hate C printf format specifiers. Alternatives?  (Read 20651 times)

0 Members and 1 Guest are viewing this topic.

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3237
  • Country: gb
Re: I hate C printf format specifiers. Alternatives?
« Reply #25 on: August 27, 2015, 04:57:58 pm »
printf is unsafe ...

printtf 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.
 

Offline Chris CTopic starter

  • Frequent Contributor
  • **
  • Posts: 259
  • Country: us
Re: I hate C printf format specifiers. Alternatives?
« Reply #26 on: August 27, 2015, 05:07:28 pm »
The 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".

That'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?
« Last Edit: August 27, 2015, 05:28:14 pm by Chris C »
 

Offline Chris CTopic starter

  • Frequent Contributor
  • **
  • Posts: 259
  • Country: us
Re: I hate C printf format specifiers. Alternatives?
« Reply #27 on: August 27, 2015, 05:18:57 pm »
Well I have created it, but … I do not find it so good

No 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.html

Note 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.
 

Offline ralphd

  • Frequent Contributor
  • **
  • Posts: 445
  • Country: ca
    • Nerd Ralph
Re: I hate C printf format specifiers. Alternatives?
« Reply #28 on: August 27, 2015, 11:41:04 pm »
Well I have created it, but … I do not find it so good

No 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.html

Note 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.

There's also Elm Chan's xprintf.
http://elm-chan.org/fsw/strf/xprintf.html
Unthinking respect for authority is the greatest enemy of truth. Einstein
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26868
  • Country: nl
    • NCT Developments
Re: I hate C printf format specifiers. Alternatives?
« Reply #29 on: August 27, 2015, 11:53:46 pm »
There's also Elm Chan's xprintf.
http://elm-chan.org/fsw/strf/xprintf.html
His 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.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 2145
  • Country: fi
  • Embedded SW/HW.
Re: I hate C printf format specifiers. Alternatives?
« Reply #30 on: August 28, 2015, 05:02:55 am »
The big problem with C interfaces like printf() isn't that they are hard to remember, it's that they are completely untyped.

exactly, for that reason I prefer to create my collection of functions, one functions for every data type

uint32_t ---> put_uint32
sint32_t ---> put_sint32
char_t ---> put_char (which can be 8 or 16bit)
string_t ---> put_string

the code is also smaller than printf, and I do not need all the support for the stack

ADA works this way, and so my embedded C

And 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.
 

Offline rs20

  • Super Contributor
  • ***
  • Posts: 2318
  • Country: au
Re: I hate C printf format specifiers. Alternatives?
« Reply #31 on: August 28, 2015, 05:44:43 am »
The big problem with C interfaces like printf() isn't that they are hard to remember, it's that they are completely untyped.

exactly, for that reason I prefer to create my collection of functions, one functions for every data type

uint32_t ---> put_uint32
sint32_t ---> put_sint32
char_t ---> put_char (which can be 8 or 16bit)
string_t ---> put_string

the code is also smaller than printf, and I do not need all the support for the stack

ADA works this way, and so my embedded C

This 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 millionths

Here's a reference example (completely untested, just dumped into the forum). A little bit recursion-heavy I grant you.

Code: [Select]
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.0625
  int32_t fixed_point = reading * 625; // Convert to fixed point with 4 decimal places
  printString("Temperature: ");
  printInt32(fixed_point, 4);
  printString(" degrees C\n");

  // Temperature: -2.4375 degrees C
}
« Last Edit: August 28, 2015, 05:49:49 am by rs20 »
 

Offline Chris CTopic starter

  • Frequent Contributor
  • **
  • Posts: 259
  • Country: us
Re: I hate C printf format specifiers. Alternatives?
« Reply #32 on: August 28, 2015, 08:57:13 pm »
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: [Select]
"%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"
 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6190
  • Country: us
Re: I hate C printf format specifiers. Alternatives?
« Reply #33 on: August 30, 2015, 04:22:10 pm »
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: [Select]
"%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"

About the same complexity of the standard, if not more complex.

Resistance is futile, join the Borg.
 

Offline Chris CTopic starter

  • Frequent Contributor
  • **
  • Posts: 259
  • Country: us
Re: I hate C printf format specifiers. Alternatives?
« Reply #34 on: August 30, 2015, 11:40:24 pm »
About the same complexity of the standard, if not more complex.

Oh well.  Thank you for the honest answer!
 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6190
  • Country: us
Re: I hate C printf format specifiers. Alternatives?
« Reply #35 on: August 31, 2015, 12:11:13 am »
Is there an online printf calculator similar to the online regex calculators?
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26868
  • Country: nl
    • NCT Developments
Re: I hate C printf format specifiers. Alternatives?
« Reply #36 on: August 31, 2015, 01:03:30 am »
Is there an online printf calculator similar to the online regex calculators?
I'm not sure whether that is useful. In my experience the interpretation of certain format specifiers depends on the implementation  :palm:
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: I hate C printf format specifiers. Alternatives?
« Reply #37 on: September 01, 2015, 10:20:01 pm »
printf and the Uncontrolled Format String  :palm: :palm: :palm:
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26868
  • Country: nl
    • NCT Developments
Re: I hate C printf format specifiers. Alternatives?
« Reply #38 on: September 01, 2015, 10:23:05 pm »
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.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: I hate C printf format specifiers. Alternatives?
« Reply #39 on: September 01, 2015, 10:23:11 pm »
a good solution in C++  :-//
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: I hate C printf format specifiers. Alternatives?
« Reply #40 on: September 01, 2015, 10:26:13 pm »
Using non-constant strings in printf won't compile in a decent C compiler

but … SierraC will  :palm: :palm: :palm:

(it's a cross compiler, DOS-x86 to m68k-baremetal
it was used by Texas Instruments for their 68K pocket calculators
TI89, TI92, etc ...)
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: I hate C printf format specifiers. Alternatives?
« Reply #41 on: September 02, 2015, 12:35:31 am »
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.

Quote
Uncontrolled Format String
I 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...
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: I hate C printf format specifiers. Alternatives?
« Reply #42 on: September 02, 2015, 02:17:39 am »
It's also interesting that in C++11 you can use std::to_string:

Code: [Select]
std::string var = "sometext" + std::to_string(somevar) + "sometext" + std::to_string(somevar); 

A bit pedantic, but safe.
 

Offline obiwanjacobi

  • Frequent Contributor
  • **
  • Posts: 988
  • Country: nl
  • What's this yippee-yayoh pin you talk about!?
    • Marctronix Blog
Re: I hate C printf format specifiers. Alternatives?
« Reply #43 on: September 02, 2015, 07:54:28 am »
It's also interesting that in C++11 you can use std::to_string:

Code: [Select]
std::string var = "sometext" + std::to_string(somevar) + "sometext" + std::to_string(somevar); 

A bit pedantic, but safe.


But not so optimal concerning memory allocations?
Arduino Template Library | Zalt Z80 Computer
Wrong code should not compile!
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: I hate C printf format specifiers. Alternatives?
« Reply #44 on: September 02, 2015, 12:10:40 pm »
But not so optimal concerning memory allocations?

unfortunately, it's the price to pay
I can't see better solutions in terms of safer solutions :-//
 

Offline codeboy2k

  • Super Contributor
  • ***
  • Posts: 1836
  • Country: ca
Re: I hate C printf format specifiers. Alternatives?
« Reply #45 on: September 02, 2015, 07:49:08 pm »
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 word :)

If 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 talk :)

Note that GNU libc++ delegates to snprintf() for all calls to std::to_string().

There is also the  C++ Format Library. Apparently it's heavily optimized for speed.

Here's some examples from the documentation:
Code: [Select]
fmt::print("Hello, {}!", "world");  // uses Python-like format string syntax
std::string s = fmt::FormatInt(42).str();   // convert to std::string

// indexed and repeated arguments
std::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
« Last Edit: September 02, 2015, 07:51:36 pm by codeboy2k »
 

Offline linux-works

  • Super Contributor
  • ***
  • Posts: 1995
  • Country: us
    • netstuff
Re: I hate C printf format specifiers. Alternatives?
« Reply #46 on: September 02, 2015, 08:15:02 pm »
Is there an online printf calculator similar to the online regex calculators?

its called python.

lol

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: I hate C printf format specifiers. Alternatives?
« Reply #47 on: September 02, 2015, 09:24:22 pm »
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.

As far as I can tell, GCC doesn't care, even with all warnings on...  What am I missing?

Code: [Select]
/tmp$ cat test.c
#include <stdio.h>

int main(int argc, char *argv[])
{
    char format[20];
    sprintf(format,"%s","Format %s\r\n");
    printf(format,"Hello!");
    return 0;
}
/tmp$ gcc -Wall -o test test.c
/tmp$ ./test
Format Hello!
/tmp$
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26868
  • Country: nl
    • NCT Developments
Re: I hate C printf format specifiers. Alternatives?
« Reply #48 on: September 02, 2015, 10:37:34 pm »
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[1] as the format string.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline Wim_L

  • Regular Contributor
  • *
  • Posts: 212
  • Country: be
Re: I hate C printf format specifiers. Alternatives?
« Reply #49 on: September 02, 2015, 10:57:58 pm »
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-security https://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.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf