Tuesday, January 10, 2012

C vs. C++'s C

Lately, compiling some cygwin-based Windows port failed here: 
char buffer[255];
snprintf(buffer, 255, "%s.png", name);

By taking into account buffer's length the snprintf command yields a more secure variant of sprintf introduced by the C99 standard.

It turned out that the problem - or course! - was not cygwin-related, but due to a slightly newer version of gcc which did not know about snprintf. Prepending the following lines of codes
#ifndef snprintf
#define snprintf(buffer, len, arg1, arg2) \
  sprintf(buffer, arg1, arg2)
#endif
fixed the problem, but that was far from being sophisticated. (Remember: we loose the important buffer-length information!)

So I started wondering why gcc had stopped supporting a long-time introduced and useful standard-conforming command. Also, enforcing standard by the -std=c99 command line option didn't help.

Of course, it didn't! Indeed, the problem was caused by the selected language dialect, but our code above was part of some C++ code. It was compiled with -std=c++98 to conform with the established C++ standard - approved one year before C99! Hence, the C-part of C++98 differed due to some last minute changes in C.

So what? Should I completely skip the nice snprintf for portability reasons? Yes, but not by using the error prone sprintf.

The real solution was to stay in (proper) C++ all the time:
std::ostringstream fullname;
fullname << name << ".png";
const char* buffer =  fullname.str().c_str();

Final philosophy:
Coding C++ code code C++ code correctly.

My best,
  Alexander