A C tidbit - Embedded.com

A C tidbit


As I have written before, everyone knows about C’s assert macro. But I have found that few embedded people make much use of it. Everyone also knows about snprintf() , yet it, too, is somewhat elusive. Do you use sprintf() or snprintf() ?

Most of the embedded code I read makes liberal use of sprintf() , yet it can be a dangerous construct. It’s all too easy to overrun the string being written. The snprintf() function makes the developer specify the max length of the string. Yet in casual surveys over the last year, nearly none of the embedded folk I asked knew of the existence of snprintf() .

The C11 standard is 700 mind-numbing pages long. All of the many C books I have are replete with examples and advice, and none approach the standard’s length. Clearly they cherry pick the best parts of the language. None covers snprintf() , though I do believe this function was added in C99 and some of those books, like the second edition of K&R, predate that version of the language.

The snprintf() function will discard all characters longer than the specified length, so is an especially attractive option when working with variably-sized elements. It can eliminate big classes of buffer overrun bugs.

The function improves maintainability. While the original developer may know with great certainty that sprintf() cannot overrun the string, later changes by others may result in the buffer’s length being shortened or the output being increased in size.

Due to NDAs (non-disclosure agreements) I can’t say much about most of the code I read. Let’s look at some publicly available software.

Freescale’s MQX RTOS, which is sprinkled with more than a little coding horror, does make use of snprintf() , though it is a function that is provided by MQX. sprintf() is much more common, though, and a lot of those functions are called with the % format specifier, which might be trouble (though no doubt the designers were scrupulous in their analysis).

What about Linux? The 3.12.6 release uses snprintf() about 6000 times, compared to 8500 for sprintf() . A superficial reading of some of this shows that in many cases it’s obvious the sprintf() is perfectly safe; that’s much less apparent for others. No doubt great care was taken to ensure buffer overruns are impossible in every circumstance.

I hope.

Though it might be tempting to use snprintf() to append text to a string, a statement of the form:

   snprintf(s, “stuff to append”, s);

… will produce an undefined result. Don’t do it.

I often put a wrapper around snprintf() to check if the string was truncated to fit in the buffer; if it was, an error is invoked (that could be an assertion or other run-time exception handler). This is an example of proactive debugging: writing code that catches bugs before a symptom appears.

Great composers expose themselves to lots of great music. Great writers read a lot of great books. And great programmers should read a lot of code to learn about the language, ways to structure the software, and the like. When you come across a construct that might be unfamiliar, like snprintf() , dig deeper.

Jack G. Ganssle is a lecturer and consultant on embedded developmentissues. He conducts seminars on embedded systems and helps companieswith their embedded challenges, and works as an expert witness onembedded issues. Contact him at . His website is.

6 thoughts on “A C tidbit

  1. “C a Reference Manual” fifth edition (Prentice Hall) does include snprintf in its description of printf and its variants including wide versions in one section that describes the common format they share and the differences between them. It uses this forma

    Log in to Reply
  2. I like to use the “strn” function wherever a similar “str” function exists (strncat, strncpy, strncmp, strlen, snprintf, etc.). They are nice when you want to be strict about manipulating strings.

    You mention that snprintf(s, “stuff to append”, s) produc

    Log in to Reply
  3. The alternative example given using strncat() doesn't quite do the trick either, as strncat() limits the number of characters copied from s2 to s1, not the overall string length. To limit overall string length you would need something along the lines of s

    Log in to Reply
  4. I've found that the strn functions were inadequate for string handling because they still allowed for buffer overflow in certain cases (strncat being a good example). So I rewrote them for our project and made them much more resistant to failure. For exa

    Log in to Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.