Cpp预处理器和文件名的基名,行号为字符串

时间:2012-11-21 18:14:13

标签: c++ gcc c-preprocessor

我想使用预处理器生成"example.cpp:34"形式的静态字符串,但__FILE__宏将扩展为"lib/example/example.cpp"__LINE__扩展为{{ 1}}作为整数。我可以使用预处理器构造所需的字符串吗? GCC扩展是可以的。

编辑这里最重要的部分是我想要一个静态C风格的字符串,所以我不能使用34函数。我想知道预处理器中是否有某种方法来复制该功能,可能还有一个boost扩展?

4 个答案:

答案 0 :(得分:2)

您可以利用相邻字符串文字连接的事实:

#define STRINGIFY(s) #s
#define FILELINE(line) __FILE__ ":" str(line)

然后像FILELINE(__LINE__)一样使用它。我不经常这样做,所以可能有一个比传递__LINE__宏更好的方法。无论如何它适用于我,测试:

#include <iostream>

#define str(s) #s
#define FILELINE(line) __FILE__ ":" str(line)

int main(int argc, const char* argv[])
{
  std::cout << FILELINE(__LINE__) << std::endl;
  return 0;
}

我明白了:

main.cpp:9

答案 1 :(得分:0)

您应该可以使用basename(),因为__FILE__扩展为const C字符串

  

<强> __ FILE __       此宏以C字符串常量的形式扩展为当前输入文件的名称。

printf ("%s:%d\n", basename(__FILE__), __LINE__);

答案 2 :(得分:0)

我不知道获取基本名称的方法,但除此之外,您可以使用字符串化预处理程序运算符'#',如:

#define M__(x,y) x ":" #y
#define M_(x,y) M__(x, y)
#define M M_(__FILE__, __LINE__)

现在M将扩展为"lib/example/example.cpp:34"(假设您将该文件放在该行的文件中,ofc:))

答案 3 :(得分:0)

嗯,不仅必须使用预处理器 - 而且最终用户也不会看到它。

如果您希望在某个文件中使用BASENAME(),请使用此标头文件basename.h

// basename.h
#include <string.h>

static size_t basename_start_calc(const char* filename)
{
    const char* base = strrchr(filename, '/');
    return base ? (base - filename + 1) : 0;
}
static inline size_t basename_start(const char* filename)
{
    static size_t retval = basename_start_calc(filename);
    return retval;
}
#define STR_(t) #t
#define STR(t) STR_(t)
#define BASENAME()  ((__FILE__ ":" STR(__LINE__)) + basename_start(__FILE__))

ideone example here

basename_start(__FILE__)将仅针对给定的源文件进行一次评估。遗憾的是,您无法在头文件中使用此解决方案 - 仅在源文件中。您可以更改它,因此可以在任何地方使用它 - 但每次都会计算给定文件名的基线开始。只需使用BASENAME() basename_start_calc(__FILE__)代替basename_start(__FILE__) ...

我相信这是最好的,你可以自动拥有。

当然,您可以手动定义每个文件宏:

#define BASENAME()  ("somefile.cpp:" STR(__LINE__))

但我不确定这是你想要的......