我想"example.cpp:34"
用预处理器生成一个静态字符串,但__FILE__
宏将扩展为整数"lib/example/example.cpp"
并__LINE__
扩展34
为整数。我可以用预处理器构造所需的字符串吗?GCC 扩展是可以的。
编辑这里最重要的部分是我想要一个静态 C 风格的字符串,所以我不能使用该basename
函数。我想知道预处理器中是否有某种方法可以复制该功能,可能带有增强扩展?
我想"example.cpp:34"
用预处理器生成一个静态字符串,但__FILE__
宏将扩展为整数"lib/example/example.cpp"
并__LINE__
扩展34
为整数。我可以用预处理器构造所需的字符串吗?GCC 扩展是可以的。
编辑这里最重要的部分是我想要一个静态 C 风格的字符串,所以我不能使用该basename
函数。我想知道预处理器中是否有某种方法可以复制该功能,可能带有增强扩展?
您可以利用连接相邻字符串文字的事实:
#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
您应该能够仅使用basename()
as__FILE__
扩展为 const C 字符串
__FILE__ 此宏扩展为当前输入文件的名称,形式为 C 字符串常量。
printf ("%s:%d\n", basename(__FILE__), __LINE__);
好吧,不仅必须使用预处理器——而且最终用户不会看到它。
当您想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示例。
basename_start(__FILE__)
对于给定的源文件将只评估一次。不幸的是,您不能在头文件中使用此解决方案 - 只能在源文件中使用。您可以更改它,因此它可以在任何地方使用 - 但是每次都会计算给定文件名的基线开始。只需使用 inBASENAME()
basename_start_calc(__FILE__)
而不是basename_start(__FILE__)
...
我相信这是你可以自动拥有的最好的。
当然,您可以在每个文件宏中手动定义:
#define BASENAME() ("somefile.cpp:" STR(__LINE__))
但我不确定这是你想要的......
我不知道获取基本名称的方法,但除此之外,您还可以使用字符串化预处理器运算符“#”,例如:
#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 :))