2

after including banned.h (one of microsoft security tools), the compiler gives me an warning that sprintf() function is not safe, and MSDN center gives me a suggestion to use sprintf_s, since my project is cross platform, I wrote a wrapper for sprintf function.

//safe function for sprintf();
void WrapperSprintf( char *buffer, const char *format, ... )
{
#ifdef _WIN32
    sprintf_s(buffer, sizeof(buffer), format,...);
#else
    sprintf(buffer, format, ...);
#endif
}

it gives me an error at line sprintf_s(buffer, sizeof(buffer), format,...);

error C2059: syntax error : '...'

Anyone knows how to write a wrapper function for sprintf_s()?

Thanks a lot.

jpo38
  • 20,821
  • 10
  • 70
  • 151
lekai
  • 23
  • 1
  • 3
  • 5
    `sizeof(buffer)` doesn't do what you expect, it yields always the same as `sizeof(char*)`. – πάντα ῥεῖ Jul 29 '14 at 06:08
  • this is a valid case to use macro. `#define my_sprintf sprintf` – Bryan Chen Jul 29 '14 at 06:09
  • 1
    If you use a `stringstream` you can forgo `sprintf` altogether. – user657267 Jul 29 '14 at 06:13
  • 1
    all those xxx_s functions added by Microsoft have one new and very important parameter: max_size. Some overloads can be used without it but with fixed-arrays (e.g. template int sprintf_s(char[N] buffer,...) which calls sprintf_s(char* butter, size_t N, ...) ...or the like). It is a pattern of strnlen vs. strlen. So, you should either change your code and always pass the 'max size' parameter and ignore it in non-windows platforms or pass some predefined max_size (like 1028) in windows platform. – firda Jul 29 '14 at 06:26
  • @πάνταῥεῖ Thanks for pointing this out :) – lekai Jul 29 '14 at 07:04

1 Answers1

14

The ... doesn't magically translate from the function declaration down to the other calls using those parameters. You have to include the variable arguments stuff and use that to call the next level down.

The steps are basically:

  • include the stdarg header.
  • declare a va_list.
  • call va_start.
  • call one of the v*printf functions.
  • call va_end.

For example, here's a little program that demonstrates how to provide a beast which writes the formatted output to a string, similar to what you seem to be after:

#include <stdio.h>
#include <stdarg.h>

void x (char *buf, char *fmt, ...) {
    va_list va;
    va_start (va, fmt);
    vsprintf (buf, fmt, va);
    va_end (va);
}

int main (void) {
    char buff[100];
    x (buff, "Hello, %s, aged %d", "Pax", 40);
    printf ("%s\n", buff);

    return 0;
}

Me, I tend to ignore Microsoft's suggestions about sprintf being unsafe. It's only unsafe if you don't know what you're doing and that can be said of any tool. If you want to become a good C programmer, you will learn the limitations and foibles of the language.

Including the one where you use sizeof on a char*, expecting it to return the size of the buffer it points to rather than the size of a pointer :-)

But, if you want to be a C++ developer, be a C++ developer. While C and C++ share a lot of commonality, they are not the same language. C++ includes a lot of C stuff primarily so that you can (mostly) take already-written C code and use it in your C++ applications.

In other words, if it's a C++ application, use std::string and std::stringstream(a) rather than char arrays and s*printf calls.

You should be writing your C++ code as if the C bits didn't exist. Otherwise, you're more a C+ programmer than a C++ one :-)


(a) Of course, knowledgeable developers will probably already be steering clear of the verbosity inherent in the stringstream stuff, and be using something like fmtlib (with the conciseness of printf but with the type safety C++ developers have come to appreciate).

Especially since it's being bought into C++20 where it will be part of the base, available to everyone.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Thanks, paxdiablo, your comment is really nice and helpful. – lekai Jul 29 '14 at 06:35
  • 1
    "It's only unsafe if you don't know what you're doing" is true, but then when you think `sizeof(buffer)` returns the size of the buffer, that sadly means "don't know what you're doing". The C++ formatting methods, while a little more work to use, avoid a lot of the severely ugly things that can happen when you use `sprintf` incorrectly. C++ is unforgiving, but C is even less tolerant of seemingly minor mistakes. – tadman Jul 29 '14 at 06:35
  • 1
    Sadly, the reason those functions had to be deprecated by default is that many developers did not know what they were doing and wrote broken code. – Billy ONeal Jul 29 '14 at 07:06
  • `sprintf` is unsafe! Just because MS provided it doesn't make it ignorable. It runs on top of template and SAL - they detect most of the bugs at compilation and Code Analysis time. – Ajay Jul 29 '14 at 07:10
  • It's not unsafe _if you know what you are doing!_ If you ensure your buffer is big enough to hold the biggest thing your format string can generate, it's as safe as anything. It's even safer than using the 'safe' variant when you get the length wrong :-) You still have to know how to use the so-called safe variants properly, and that's little different from knowing how to use the others. – paxdiablo Jul 29 '14 at 07:19