如何让预处理器为__LINE__关键字生成一个字符串?

Dmi*_*riy 29 c++ visual-studio-2008 c-preprocessor

__FILE__由C++预处理器替换为"MyFile.cpp".我想__LINE__用"256"字符串替换而不是256整数.不使用我自己的书面函数

toString(__LINE__);
Run Code Online (Sandbox Code Playgroud)

那可能吗?我该怎么做?

VS 2008

编辑我想自动查找和替换所有throw;语句

throw std::runtime_error(std::string("exception at ") + __FILE__ + " "+__LINE__);
Run Code Online (Sandbox Code Playgroud)

在我的消息来源.如果我使用宏或函数转换__LINE__为字符串,我将需要手动修改每个源文件.

zwo*_*wol 61

你需要双扩展技巧:

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

/* use S__LINE__ instead of __LINE__ */
Run Code Online (Sandbox Code Playgroud)

多年后的附录:最好不要采取一种方法来避免可能在异常处理路径中分配内存的操作.鉴于上述情况,您应该能够写作

throw std::runtime_error("exception at " __FILE__ " " S__LINE__);
Run Code Online (Sandbox Code Playgroud)

它将在编译时而不是运行时执行字符串连接.它仍将在运行时构造一个std :: string(隐式),但这是不可避免的.

  • @geotavros:嗯`__LINE__`是一个宏,所以使用宏来转换它是最自然的.你可以在运行时转换它,但为什么这样做? (2认同)

Rob*_*obᵩ 8

编辑:为了回应其他答案的请求,我添加了一个非宏版本:

#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());
}
Run Code Online (Sandbox Code Playgroud)

  • g ++ - 4.5 -O0将转换编译为14行程序集+ 20作为展开块.这个_calls_函数使用streambuffers生成一个新的动态std :: string(堆分配),创建一个15级深度的调用图; 换句话说,不要用它跟踪行号!CPP MACRO很难看,但会导致静态分配的常量char*,运行时开销为零._(来源:objdump,g ++ -S和callgrind)_ (8认同)
  • 分析最后一行的繁忙循环:58%`lexical_cast`,8%`~basic_string()`,32%f(); 仅分析MACRO版本的繁忙循环:f()中98.88%的时间; 优化-O4不会改变比率; 只是内联深度因内联而减少 (5认同)