The system() function, then, should always be given a fixed command line, with any unknowns filled in by the shell using parameter expansion, to be sure of getting the correct results. Even better is to use execve() directly, if possible. (Perl provides a way of doing this: system() can take a list.)
This isn't always possible, of course: in some cases, the command line to use will be configurable, with the syntax for indicating replaceable parameters already fixed, as we'll see in the section called “Desktop Entries”. But even in those cases, it is possible to transform the problem into one that can be solved using a known command line (or at least, one constructed from known components).
If you are going to be writing some code that you think needs to modify a command line, there are some library functions around that seem like they could help you avoid making mistakes in the implementation. Let's take a look at some of the candidates.
In the popt package, there is a function named poptParseArgvString(), which will convert a command line into an argument vector ‘using rules similar to normal shell parsing’. Unfortunately, parameter expansion is not supported, and so it is no use the for job at hand.
Similarly, glib has a function named g_shell_parse_argv(), but it also misses the point: parameter expansion is not supported.
To find a function that really does the job, we need look no further than POSIX, which specifies the wordexp() function. (For a detailed discussion of the wordexp() function, see the GNU C library manual). This function does perform parameter expansion, and a lot more besides. It can also be told not to perform command subsitution, for additional safety.