1

Sorry, I know this is really basic, but I don't know how to search it the proper way, so here we go. I'm trying to call MessageBoxA, and I want the message to replace '%s' with something else. Example:

MessageBoxA(0, TEXT("You have %s items"), "title", 0);

Can anyone help me? And once again, I know this is really basic, sorry.

2
  • 2
    You gotta build the string. sprintf, stringstream, ect. Commented Sep 18, 2013 at 17:59
  • So I use: MessageBox(0, TEXT(sprintf("You have %s items", itemNum)), "title", 0); ??? Commented Sep 18, 2013 at 18:02

4 Answers 4

8

You have to build the string yourself. In C++, this is typically done with std::ostringstream, e.g.:

#include <sstream>
...

std::ostringstream message;
message << "You have " << numItems << " items";
MessageBoxA(NULL, message.str().c_str(), "title", MB_OK);

In C, this is typically done with snprintf(3):

#include <stdio.h>
...

char buffer[256];  // Make sure this is big enough
snprintf(buffer, sizeof(buffer), "You have %d items", numItems);
MessageBoxA(NULL, buffer, "title", MB_OK);
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you so much! I'll vote up within 9 minutes :) But imagine that I want to do the same in other cases, something with va_list would help?
+1, but I always find in these examples to show which includes should be included. Inclusively. Inclined to do so. :)
Since the OP is probably using Windows, if they are using MFC, the CString family of classes also has a Format function that behaves in a very similar fashion to the sprintf family.
@user2696223 See my answer for the va_list variant you're likely looking for.
0

You can write a utility function to build a std::string from a printf-style format:

#include <cstdio>
#include <cstdarg>
#include <string>
#include <vector>

std::string build_string(const char* fmt, ...) {
    va_list args;
    va_start(args, fmt);
    size_t len = vsnprintf(NULL, 0, fmt, args);
    va_end(args);
    std::vector<char> vec(len + 1);
    va_start(args, fmt);
    vsnprintf(vec.data(), len + 1, fmt, args);
    va_end(args);
    return std::string(vec.begin(), vec.end() - 1);
}

With this function in place, you can create arbitrary strings and pass pointers to their contents as downward-arguments:

MessageBoxA(0, build_string("You have %d items", item_count).c_str(), "title", 0);

It has the advantage of simplicity (several lines of code using only stdio without dependency on iostreams), and has no arbitrary limits on the size of string.

5 Comments

I cannot understand why this is the accepted answer for a C++ question. Adam Roosevelt's is arguably the correct answer.
But I like to use this way with va_list, it's better.
@Moo-Juice I fail to see what you think is wrong with the answer. It is correct, fast, robust, and solves the OP's problem, satisfying including the desired use of printf-style format strings (which are popular in C++ as much as in C). In addition to the above, it uses the C++ facilities such as STL vectors and strings to ensure safety and robustness, and has no arbitrary limits on string size. How is that answer "less correct" than another one?
The robustness is quite limited because it suffers from the type-insafety of ...; e.g. on some implementations you can use this to print std::string but only if they're long enough (!) That's not what I call robust. Fast? Meh. The %s is interpreted at runtime, even though the correct type is known at compile time.
Fast compared to stringstream based solutions, which are (at least on several popular implementations) measurably and significantly slower — in some cases an order of magnitude — than a call to snprintf. Type-unsafety inherent to the snprintf format is obviously shared by any solution based on it.
0

For MessageBoxA it is:

char szBuf[120];
snprintf(szBuf,120, "You have %s items",nItemCount);
MessageBoxA(0, szBuf, "title", 0);

It is ugly, but it will fit your need.

1 Comment

You're not passing snBuf to the Messagebox
0

Use boost::format.

In your example: MessageBoxA(0, (boost::format("You have %1 items") % "title").c_str(), 0);

One advantage is that you don't need to remember all those %s codes anymore, another is that you're no longer limited by the set of built-in flags.

The ( ).c_str() is needed because MessageBoxA is a C interface, not C++, and c_str() converts a C++ string to a C string.

Comments

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.