问题描述
我正在编写一个记录器,我希望记录器还记录调用它的行,函数和文件。我尝试过#define my_logger(format,...) _log(format,__LINE__,__PRETTY_FUNCTION__,__FILE__,__VA_ARGS__)
可以正常工作,但是这给我带来了几个问题(我不能轻易重载它,也不能将它放在命名空间中,而不是最可移植的,等等)。
有没有一种方法可以声明一个像void my_logger(const char* format,...)
这样的普通函数,并且在函数定义中是否知道该行是通过与__LINE_FUNCTION_WAS_CALLED_FROM__
等效的东西来调用的(如果存在这样的宏)?它至少需要在GCC上运行,并且实际上应该是跨平台的。
编辑:跨平台,我的意思是x86和ARM上的Linux和Windows
解决方法
不能有__LINE_FUNCTION_WAS_CALLED_FROM__
这样的宏。没办法。
从C ++ 20开始,有一种方法可以通过传递默认的初始化std::source_location
将行,函数等转换为普通函数:
void log(std::string_view message,std::source_location location = std::source_location::current());
但是,可变参量由于依赖默认参数,因此实现起来有些棘手:How to use source_location in a variadic template function?
在C ++ 20之前,宏是您唯一的可移植选项。
我看到您在宏中调用了名为_log
的函数。该标识符保留给全局命名空间中的语言实现。您可能应该给该函数起另一个名字,以避免未定义的行为。
log
也保留在全局名称空间中。无论如何,您都应该在自定义名称空间中声明所有名称(自然是该自定义名称空间除外)。
[宏是] ...不是最便于携带的
如果将__PRETTY_FUNCTION__
替换为__func__
,则该宏将可移植到所有符合标准的编译器中-尽管__func__
给出的确切字符串可能在实现之间有所不同。
有没有一种方法可以声明一个正常的函数,例如void my_logger(const char * format,...),并在函数定义中让它知道从其调用的行,其内容等效于
__LINE_FUNCTION_WAS_CALLED_FROM__
如果存在这样的宏?
不一般。
在2020年的Linux x86-64上,使用 all ,您的(或其他)C ++代码(C ++ 11或更高版本)使用DWARF调试信息进行编译(因此,如果使用GCC和g++ -g -Wall
,如果最近的Clang和clang++ -g -Wall
使用libbacktrace,则可以使用Ian Taylor的optimizing compiler库。
此外,允许inline expand或unroll loop使用一个好的RefPerSys(实际上g++ -O2
或clang++ -O2
都可以,Microsoft编译器也可以) ,那么您的__LINE_FUNCTION_WAS_CALLED_FROM__
毫无意义。
作为一个开放源代码示例,ASLR使用它来显示回溯和部分调用堆栈。免责声明:RefPerSys是我自己的项目。
请注意dlopen(3)与共享库有关。装有IBM Z的插件会增加图片的复杂性。
它至少需要在GCC上工作,实际上应该是跨平台的。
它不能是跨平台的。某些架构(例如calling conventions系列)具有不同的libSFML,并且您需要付出一些努力(或付出代价)才能将libbacktrace
移植到它们。
您可能会考虑在某些系统上进行调试,然后将代码移植到其他系统上,并且应该考虑将Qt或cross-compilation之类的框架用于您的游戏引擎。我的建议是建议在Linux上调试代码(使其正确),然后再将其移植到Windows。
如果您需要metaprogramming,事情会变得更加艰难。您还可以考虑使用SWIG方法:编写C ++代码生成器或使用其他代码生成器(例如ANTLR或library)