C/C++: Perform safe sprintf 1


The following function accepts the address of a char * buffer, the formatting string for printf along with all the parameters needed to fill the formatting string and updates the location of the buffer to point at the final formatted string.

safe_sprintf.c (92 downloads)

This code does not require the user to perform malloc before filling in the buffer. Using vsnprintf (variation of snprintf for variable arguments) it will automatically find the correct size that the buffer should have, allocate the space, switch the pointer of the buffer and prepare the final string using the formatting arguments.

In our header file, we used the following pre-processor directives around our declarations

#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif

to allow c++ code to call our function.

safe_sprintf.c (92 downloads)

Source file (string_helpers.c)

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "string_helpers.h"

int safe_sprintf(char ** buffer, const char *format, ...) {

  va_list arguments;
  //The va_start(va_list arguments, last) macro initializes and must be called first.
  //The argument last is the name of the last argument before the variable argument list, that is, the last argument of which the calling function knows the type.
  va_start (arguments, format);

  //Upon successful return, vsnprintf returns the number of characters printed (excluding the null byte used to end output to strings).
  //For that reason we add one at the end of the length.
  const int length = vsnprintf(NULL, 0, format, arguments) + 1;

  //Each invocation of va_start() must be matched by a corresponding invocation of va_end() in the same function.
  // After the call va_end(arguments) the variable arguments is undefined.
  // Multiple traversals of the list, each bracketed by va_start() and va_end() are possible. va_end() may be a macro or a function.
  va_end (arguments);

  if (*buffer) {
    free(*buffer);
  }
  if (!(*buffer = malloc(length * sizeof(char)))) {
    return EXIT_FAILURE;
  }

  va_start(arguments, format);
  vsnprintf(*buffer, (size_t) length, format, arguments);
  va_end (arguments);

  return EXIT_SUCCESS;
}

Header file (string_helpers.h)

#ifndef GM_S_LITTLE_HELPERS_STRING_HELPERS_H
#define GM_S_LITTLE_HELPERS_STRING_HELPERS_H

#ifdef __cplusplus
extern "C" {
#endif

int safe_sprintf(char ** buffer, const char *format, ...);

#ifdef __cplusplus
}
#endif

#endif //GM_S_LITTLE_HELPERS_STRING_HELPERS_H

Usage example (main.cpp)

#include <iostream>
#include "string_helpers.h"

int main() {

  char * buffer;
  safe_sprintf(&buffer, "Hello, World!\nFrom Line %d in function %s of the file %s.", __LINE__, __func__, __FILE__);
  printf("%s", buffer);
  return 0;
}

safe_sprintf.c (92 downloads)

This post is also available in: Greek


Leave a Reply

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

One thought on “C/C++: Perform safe sprintf

  • Anatoliy

    As i understand this function is main in web development. So is discussed so widely! I hate web development for some reasons. But it doesn’t matter. As to this code. I remember I wrote something like that but that was many years ago. No I don’t do that never. There are more suitable functions that do all that match better a-print functions, The get double point string buffer. There are two:
    int asprintf(char **strp, const char *fmt, …) and
    int vasprintf(char **strp, const char *fmt, va_list ap).
    strp in a pointer to buffer of string buffer. These functions just allocate enough memory and place all output into it. The value returned is a memory allocated size. You need to do some else, If error return -1. You need GNU extension or BSD. This condition usual easy to satisfy. If no use code above. But I suspect all well. by the way allocate arbitrary size of memory not desired. Better align capacity to some round value. I use nearest 2**n size. This value gives better result. So It quick enough and least too.