0

I am trying to write a macro to expand the contents of a struct:

struct Str
{
    int a;
    float f;
    char *c;
};
Str s = {123, 456.789f, "AString"};

#define STRINGIFY_STR(x) ... // Macro to stringify x which is an instance of Str

printf("%s", STRINGIFY_STR(s));

desired output: [a: 123, f:456.789, c:AString]

Is it possible to write a macro that does this? If it is, then how?

FearLeslie
  • 31
  • 5
  • 1
    stringify? macros? Why not simply add a `toString` method to your object or a free function which takes a const reference to achieve this? You could even just use `std::ostringstream` if performance is not a concern. – AJG85 Jun 16 '12 at 00:58
  • 1
    IS there a particular reason you need a macro? It would be better to write `operator<<` for the Str class. – Martin York Jun 16 '12 at 01:09

4 Answers4

6

Is there a reason you want to do this as a macro?

You should write a function to perform this action instead of using the preprocessor.


Depending on your goals, there are a few options. The boost formatting library provides a great toolkit to build the formatted string. You could always overload operator<< to provide clean output, as well.

If you're doing this in pure C, the sprintf family of methods work for creating formatted output.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • This doesn't really answer the question. – Luchian Grigore Jun 16 '12 at 00:57
  • @LuchianGrigore, It could use a bit of code, but in the end it's the same syntax (or better) for a working output or string. – chris Jun 16 '12 at 00:58
  • 1
    @LuchianGrigore I tried to add some useful information for options -but I guess my problem is that I feel that directly answering the question is promoting something that's a bad practice in general. – Reed Copsey Jun 16 '12 at 01:00
  • I don't want to write a function for this because then I would have to allocate memory dynamically or pass a buffer to the function to hold the string. I just thought it could be possible to expand the struct into a string with a macro, am I wrong? – FearLeslie Jun 16 '12 at 01:01
  • @FearLeslie Even with a macro, you'd be creating a buffer of some form to hold the string data, even if it's on the stack. How is that different than passing a stack allocated buffer? – Reed Copsey Jun 16 '12 at 01:03
  • 1
    @FearLeslie Don't "fear" unnecessarily :-) – Jagannath Jun 16 '12 at 01:04
  • @Reed Copsey: may be you are right. Still, out of curiosity, how would one go about writing such a macro? – FearLeslie Jun 16 '12 at 01:05
  • @FearLeslie The macro would just be building a string - so any of the techniques you'd use to do it in a function would have to be expanded into the macro. – Reed Copsey Jun 16 '12 at 01:08
1

This is quite gross, and only works on gcc/g++.

#define STRINGIFY_STR(x) \
    std::string(({ std::ostringstream ss; \
                   ss << "[a: " << x.a \
                      << ", f: " << x.f \
                      << ", c: " << x.c << "]"; \
                   ss.str(); })).c_str()

You have to create the string from the values. Please don't do it this way. Please follow Reed's advice.

Here is how I would modify your struct to allow it to be pretty printed:

struct Str
{
    int a;
    float f;
    char *c;

    std::ostream & dump (std::ostream &os) const {
        return os << "[a: " << a
                  << ", f: " << f
                  << ", c: " << c << "]";
    }
};

std::ostream & operator << (std::ostream &os, const Str &s) {
    return s.dump(os);
}

Str s = {123, 456.789f, "AString"};

Now, to print out s, you can use std::cout:

std::cout << s << std::endl;

Or, if you really want a string:

std::stringstream ss;
s.dump(ss);
puts(ss.str().c_str());
jxh
  • 69,070
  • 8
  • 110
  • 193
1
struct stringify
{
    operator std::string() const
    {
        return str ;
    }
    std::string str ;
};

template < typename T > stringify operator+ ( stringify s, const T& object )
{
    std::ostringstream stm ;
    stm << object ;
    if( !s.str.empty() && !std::isspace( *s.str.rbegin() ) ) s.str += ' ' ;
    s.str += stm.str() ;
    return s ;
}
aqwerty
  • 11
  • 1
0

I'm also against the approach, but to answer the question:

#define STRINGIFY_STR(x) \
   (std::string("[a: ") + std::to_string((long double)x.a) \
  + std::string(", f:") + std::to_string((long double)x.f) \
  + std::string(",c: ") + x.c + std::string("]") ).c_str()

I suggest writing a member function that does this though.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625