32

__FILE__ is replaced with "MyFile.cpp" by C++ preprocessor. I want __LINE__ to be replaced with "256" string not with 256 integer. Without using my own written functions like

toString(__LINE__);

Is that possible? How can I do it?

VS 2008

EDIT I'd like to automatically Find and Replace all throw; statements with

throw std::runtime_error(std::string("exception at ") + __FILE__ + " "+__LINE__);

in my sources. If I use macro or function to convert __LINE__ into a string I'll need to modify each source file manually.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Dmitriy
  • 5,357
  • 8
  • 45
  • 57
  • 1
    About the edit: `throw;` is called *rethrow* and preserves the current exception. Replacing all rethrows with `runtime_error` is pretty bold, are you sure that's what you want? And why can't you call a function-like macro in the replace string? Just add the macro to a header, or use find-and-replace to insert a new header atop every source file. – Potatoswatter Apr 13 '11 at 11:47
  • Yes, I'm sure. These throw statements are incorrect and cause terminate(). – Dmitriy Apr 13 '11 at 14:50

2 Answers2

64

You need the double expansion trick:

#define S(x) #x
#define S_(x) S(x)
#define S__LINE__ S_(__LINE__)

/* use S__LINE__ instead of __LINE__ */

Addendum, years later: It is a good idea to go a little out of one's way to avoid operations that may allocate memory in exception-handling paths. Given the above, you should be able to write

throw std::runtime_error("exception at " __FILE__ " " S__LINE__);

which will do the string concatenation at compile time instead of runtime. It will still construct a std::string (implicitly) at runtime, but that's unavoidable.

zwol
  • 135,547
  • 38
  • 252
  • 361
  • Is there a way without using a macro? Or it is the only way? – Dmitriy Apr 12 '11 at 21:01
  • 2
    @geotavros: Well `__LINE__` is a macro, so using macros to transform it is most natural. You could convert it at run-time, but why do that? – GManNickG Apr 12 '11 at 21:09
  • I think they're maybe looking for a compiler switch that makes `__LINE__` itself be a string rather than a number? But I would guess there isn't one (I don't know MSVC inside and out, though) – zwol Apr 12 '11 at 21:35
  • ... Depending what you're doing, conversion at run time may be the right option -- frex, an `assert`-like macro that winds up passing `__LINE__` to `printf` would chew up a bunch of data space with short strings if you stringified `__LINE__` at compile time. – zwol Apr 12 '11 at 21:41
  • Yuck! This preprocessor is awesome. I mean horrible. I mean awesome. – Dacav Sep 18 '18 at 22:00
7

EDIT: In response to request on the other answer, I added a non-macro version:

#include <iostream>
#include <boost/lexical_cast.hpp>
#include <string>

#define B(x) #x
#define A(x) B(x)

void f(const char *s) {
std::cout << s << "\n";
}

int main() {

   f(A(__LINE__));
   f(boost::lexical_cast<std::string>(__LINE__).c_str());
}
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • 9
    g++-4.5 -O0 compiles the cast into 14 lines of assembly + 20 for the unwind block. This _calls_ the function which uses streambuffers to generate a new dynamically std::string (heap-allocated), creating a callgraph of 15 levels deep; in other words, don't use this to trace line numbers with! The CPP MACRO is ugly, but results in a statically allocated constant char* with zero runtime overhead. _(source: objdump, g++ -S and callgrind)_ – sehe Apr 12 '11 at 23:03
  • 6
    Profiling a busy loop of the last line: 58% `lexical_cast`, 8% `~basic_string()`, 32% f(); Profiling a busy loop of the MACRO version only: 98.88% of time in f(); Optimizing -O4 changes nothing in the ratios; just the callgraph depth is reduced due to inlining – sehe Apr 12 '11 at 23:54