使用C++11,您有几个选项。首先让我们定义:
constexpr int32_t basename_index (const char * const path, const int32_t index = 0, const int32_t slash_index = -1)
{
return path [index]
? ( path [index] == '/'
? basename_index (path, index + 1, index)
: basename_index (path, index + 1, slash_index)
)
: (slash_index + 1)
;
}
如果您的编译器支持语句表达式,并且您想要确保基本名称计算是在编译时进行的,您可以这样做:
如果您的编译器支持语句表达式,并且您想要确保基本名称计算是在编译时进行的,您可以这样做:
// stmt-expr version
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
#define __FILELINE__ ({ static const int32_t basename_idx = basename_index(__FILE__);\
static_assert (basename_idx >= 0, "compile-time basename"); \
__FILE__ ":" STRINGIZE(__LINE__) ": " + basename_idx;})
如果你的编译器不支持语句表达式,你可以使用以下版本:
// non stmt-expr version
#define __FILELINE__ (__FILE__ ":" STRINGIZE(__LINE__) ": " + basename_index(__FILE__))
使用非stmt-expr版本时,gcc 4.7和4.8会在运行时调用basename_index函数,因此最好使用带有stmt-expr版本的gcc。ICC 14对两个版本都生成了最佳代码。ICC13无法编译stmt-expr版本,并对非stmt-expr版本生成次优代码。
为了完整起见,这里将所有代码放在一个地方:
#include <iostream>
#include <stdint.h>
constexpr int32_t basename_index (const char * const path, const int32_t index = 0, const int32_t slash_index = -1)
{
return path [index]
? ( path [index] == '/'
? basename_index (path, index + 1, index)
: basename_index (path, index + 1, slash_index)
)
: (slash_index + 1)
;
}
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
#define __FILELINE__ ({ static const int32_t basename_idx = basename_index(__FILE__); \
static_assert (basename_idx >= 0, "compile-time basename"); \
__FILE__ ":" STRINGIZE(__LINE__) ": " + basename_idx;})
int main() {
std::cout << __FILELINE__ << "It works" << std::endl;
}
__FILE__
展开为命令行中给定的文件名,可以是绝对路径或相对路径。区别可能在于 Makefile 中。__BASE_FILE__
是 gcc 扩展,与之不同的是,它只返回最外层的文件名,而不是任何#include
的内容。 - Keith Thompson