1

In c++, is it possible and safe to use macros in system calls? Take the following code for example:

#define WINX 54
#define WINY 30

int main()
{
system("mode con lines=WINY cols=WINX");
...

Would that work and be safe to use in code? Or would I have to manually construct a string?

4 Answers 4

5

A macro will not expand inside a string literal. Instead, you can use another macro to expand a macro into a string literal, and use string literal concatenation to create the desired string:

#define STR2(x) STR(x)
#define STR(x) #x

const char *cmd = "mode con lines=" STR2(WINY) " cols=" STR2(WINX);
system(cmd);

STR2 expands the provided argument (e.g. WINY) into what it is defined to be and then passes it to STR. STR just uses the stringifying macro operator, and its result is a string literal. Adjacent string literals are concatenated into a single string by the compiler before the code is tokenized and compiled into object code.

If the macros are something more complex than simple numbers, then you need to manually construct a string. In C++, the easiest way is to use ostringstream (from <sstream>):

std::ostringstream oss;
oss << "mode con lines=" << WINY << " cols=" << WINX;
system(oss.str().c_str());
4
  • It's worth mentioning that STR2(WINY) expands to a string literal, and adjacent string literals are joined together in an early phase of compilation. You might also want to mention that macros are not expanded inside string literals, which is why this approach is necessary. Commented Jun 12, 2013 at 19:42
  • Shouldn't the preprocessor construct the string before it is passed to system, so I should be able to use system("mode con lines=" STR2(WINY) " cols=" STR2(WINX)); ? Commented Jun 12, 2013 at 19:44
  • @user2403132: Yes, but you have to tell the preprocessor to construct the string; that's what "mode con lines=" STR2(WINY) " cols=" STR2(WINX) does. (You could pass that directly to system(); the cmd declaration isn't really necessary.) Commented Jun 12, 2013 at 19:46
  • @user2403132: Yes to what Keith says. I separated it into a separate variable just to make it less cluttered, but it is not necessary.
    – jxh
    Commented Jun 12, 2013 at 19:49
3

Macros certainly don't expand in strings. So, this

system("mode con lines=WINY cols=WINX");  

won't expand into

system("mode con lines=30 cols=54");
1

If you don't need the actual decimal value of WINX and WINY, you can concatenate static strings and save resources during execution time:

#define WINX "54"
#define WINY "30"

int main()
{
system("mode con lines=" WINY " cols=" WINX);
0

You'll have to manually construct a string.

For example:

char command[100];
int result;
sprintf(command, "mode con lines=%d cols=%d", WINY, WINX);
result = system(command);

Don't forget the required include directives:

#include <stdio.h>
#include <stdlib.h>

Consult your system's documentation for the meaning of the value returned by system.

Make sure the command array is big enough to hold the full command -- or, probably better, use std::string instead. jxh's answer shows how to do this.

3
  • I suppose it doesn't matter for the OP, but there is no real reason to do this in runtime.
    – Lundin
    Commented Jun 12, 2013 at 19:35
  • C++ does not define a version of sprintf that works on a std::string.
    – jxh
    Commented Jun 12, 2013 at 19:41
  • @jxh: I know, I meant to suggest building a std::string in some other way. jxh's answer shows how to do this, and is better than mine. Commented Jun 12, 2013 at 19:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.