Being a parent now, I found this commercial pretty funny.
In C/C++, macros that take a variable number of arguments (called variadic macros) can be very useful. Having printf-style macros just makes certain things easier to read and understand. Below I’ll describe how to do this in a way that works on Windows and Linux, as well as supports empty argument lists.
Example
Consider the following log method:
void WriteLog( const LOG_LEVEL level, const char* file, const int line, const char* format, ... );
Pretty straight-forward: it allows you to specify the log level (NOTICE, WARNING, ERROR, etc), a file name and line number, and a user-defined description in “printf” format. To log a warning message, you would type:
WriteLog( LL_WARNING, __FILE__, __LINE__, "[WARNING] Failed to import descriptor '%s:%i'!", _descriptor, _id );
The entry in the log file would look like:
Core.cpp:715 [WARNING] Failed to import descriptor 'timing-engine'!
Creating a Variadic Macro
Calling WriteLog directly works fine, but it’s pretty verbose and annoying to use. One way to make it simpler is to wrap WriteLog with a variadic macro:
#define LOG_WARNING( format, ... ) \\
WriteLog( LL_WARNING, __FILE__, __LINE__, "[WARNING] " format, ##__VA_ARGS__ );
Then the example above would become:
LOG_WARNING( "Failed to import descriptor '%s:%i'!", _descriptor, _id );
The macro automatically fills in the file and line number where the log message was generated, and the log level is specified by the macro name (LOG_WARNING). This is much more straight-forward and I believe it makes the code easier to read.
Notice that __VA_ARGS__ is used to get the variable argument list and pass it to WriteLog. During compilation, the preprocessor replaces __VA_ARGS__ with the comma-separated list of arguments. The ‘##‘ that prefixes __VA_ARGS__ is vital if you want your macro to work like you expect. Without it, you would be required to have at least one argument after the format string. ’##‘ has a special meaning in this case: it causes the preceding comma to be deleted if there are no variable arguments. Without this, the following line would generate a syntax error:
LOG_WARNING( "This would cause a syntax error" );
Prefixing __VA_ARGS__ with ‘##‘ allows the above code to work just fine.
We ran into a weird problem the other day where our Linux video display appliance would lose audio support when the process was restarted. The audio was supposed to play through a custom joystick-keyboard that was attached via USB (the keyboard is used by security guards to PTZ cameras, control monitors, etc). The audio could be heard just fine when the box first booted, but if the application restarted audio would be lost.
Looking at the logs, we found that our audio pipeline was failing to open /dev/dsp on the restart. We then used lsof to list the open file descriptors to see which process currently held /dev/dsp:
# lsof | grep /dev/dsp
ntpd 18857 root 16u CHR 14,3 180099 /dev/dsp
What!?!?… why the heck is NTP opening the sound device and how did it steal it from us??? After some discussion we started remembering a problem in the past with ntpd stealing our SNMP diagnostics port. This just didn’t make any sense.
Digging into our appliance code, we found this line:
system( "service ntpd restart" );
This would be called each time we were notified by the security system that the NTP server address had changed (which fired once each time the process was started so we could get the initial address). But this still didn’t explain why NTP took over ownership of our file descriptors on restart.
Long story short: system() is implemented as fork() followed by execv(). By default, fork() gives a copy of the parent’s file descriptors to the child process (i.e. the ntpd child process got a copy of the /dev/dsp file descriptor). To prevent this, you have to set the FD_CLOEXEC flag on the file desciptors you don’t want copied.
For example:
fd = open( "/dev/dsp", O_RDWR );
fcntl( fd, F_SETFD, FD_CLOEXEC );
Conclusion: setting the FD_CLOEXEC flag on the /dev/dsp file descriptor fixed the problem for audio. However, most of the other file desciptors still got owned by ntpd. Did we go back and set the FD_CLOEXEC flag on all file descriptors, you ask? Nope. It turns out we had a script monitoring the NTP config file and restarting ntpd for us when the file got updated… we just had to update the config file and remove the system( "service ntpd restart" ) call.
Oh, and the reason audio worked on first boot but not subsequent restarts was due to a weird race condition around when /dev/dsp got opened.
The New York Times has a great article on a new system developed by IBM named “Watson”. It’s a computer system that’s scraped 10′s of millions of documents from the Internet and compiled a massive database of knowledge. It used natural language parsing to interpret questions and generate answers. The cool thing is that it beat former Jeopardy contestants 4 out of 6 times in mock Jeopardy session. Here are some quotes from the article I found interesting:
It displayed remarkable facility with cultural trivia (“This action flick starring Roy Scheider in a high-tech police helicopter was also briefly a TV series” — “What is ‘Blue Thunder’?”), science (“The greyhound originated more than 5,000 years ago in this African country, where it was used to hunt gazelles” — “What is Egypt?”) and sophisticated wordplay (“Classic candy bar that’s a female Supreme Court justice” — “What is Baby Ruth Ginsburg?”).
Software firms and university scientists have produced question-answering systems for years, but these have mostly been limited to simply phrased questions. Nobody ever tackled “Jeopardy!” because experts assumed that even for the latest artificial intelligence, the game was simply too hard: the clues are too puzzling and allusive, and the breadth of trivia is too wide.
With Watson, I.B.M. claims it has cracked the problem — and aims to prove as much on national TV. The producers of “Jeopardy!” have agreed to pit Watson against some of the game’s best former players as early as this fall (emphasis mine). To test Watson’s capabilities against actual humans, I.B.M.’s scientists began holding live matches last winter.
I’d definitely watch that episode… especially if Watson was pitted against Ken Jennings.
Under the hood:
[IBM's] main breakthrough was not the design of any single, brilliant new technique for analyzing language. Indeed, many of the statistical techniques Watson employs were already well known by computer scientists. One important thing that makes Watson so different is its enormous speed and memory. Taking advantage of I.B.M.’s supercomputing heft, Ferrucci’s team input millions of documents into Watson to build up its knowledge base — including, he says, “books, reference material, any sort of dictionary, thesauri, folksonomies, taxonomies, encyclopedias, any kind of reference material you can imagine getting your hands on or licensing. Novels, bibles, plays.”
The full article is worth the read.
Having printf-style functions is very useful. I find myself periodically having to remember how to write variable argument functions, so I decided to just blog about it.
EDIT (4/18/2011): Simple Version That Just Prints
#include <stdarg.h>
void Foo( const char* format, ... )
{
va_list args;
va_start( args, format );
vprintf( format, args );
va_end( args );
}
End Edit
#include <stdarg.h> // or <cstdarg>
// Hide annoying naming differences between Windows and other platforms
#ifdef WIN32
#define my_vsnprintf _vsnprintf
#else
#define my_vsnprintf vsnprintf
#endif
// The function
void Foo( const char* format, ... )
{
// Parse the argument list
va_list args;
va_start( args, format );
// Calculate the final length of the formatted string
int len = my_vsnprintf( 0, 0, format, args );
// Allocate a buffer (including room for null termination)
char* target_string = new char[++len];
// Generate the formatted string
my_vsnprintf( target_string, len, format, args );
/* Do something with the formatted string */
// Clean up
delete [] target_string;
va_end( args );
}
Gotchas
We ran into a problem with vsnprintf() using the Denx Linux distro on a PowerPC processor: vsnprintf( 0, 0, format, args ) would modify the va_list, which would cause a crash on the second call to vsnprintf()… the one that does the actual formatting. The work-around is to make a temporary copy of the va_list when determining the formatted string length:
va_list args_copy;
va_copy( args_copy, args );
int len = my_vsnprintf( 0, 0, format, args );
va_end( args_copy );
My friend Nick brought this video to my attention. It shows how small $100 million dollars is compared to the entire US budget. What really stood out to me was how much of the budget is dominated by welfare handouts… looks like over 80%. I guess we are “all socialists now.”
(requires Adobe Flash plugin… click HERE to watch it on YouTube)
I found my Charlie Hunter CD recently and I’ve been enjoying listening to him again. He’s an amazing musician apart from the fact that he plays the bass and guitar simultaneously. YouTube didn’t exist when I first got into him, and it’s nice now to be able to watch him play. Enjoy!
(requires Adobe Flash plugin… click HERE to watch it on YouTube)
If this video ever gets deleted from YouTube, you can download it HERE.
After some digging, I finally found out how to create a regex for Sed (stream editor) that will find a line that does NOT contain a particular string. First, I used ‘find’ to list all the *.cpp files in my source tree:
find . -name “*.cpp” -print
Then I piped the files to ‘sed’ via ‘xargs’ (Note: replace the ‘-e’ with ‘-i’ to actually modify the files inline):
find . -name “*.cpp” -print | xargs sed -e ‘/STRING_TO_INGORE/! { d }’
The trick is adding the ‘!’ (exclamation point) after the search expression. Without it, ‘sed’ would think you only want lines with the string, not without it.
This is different than another syntax I’ve seen used: /(?!STRING_TO_IGNORE)/.
Here’s another example. Say you want to replace STRING1 with STRING2 only if the first characters of the line (ignoring white space) are NOT “//”… i.e. skip the string replacement in code comments:
sed -i ‘/^[ \t]*\/\/.*/! { s/STRING1/STRING2/ }’
NOTE: ‘[ \t]*’ means ignore 0 or more spaces or tabs.



