有没有办法在C ++中不用宏就能获得行号?

问题描述

我正在编写一个记录器,我希望记录器还记录调用它的行,函数文件。我尝试过#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调试信息进行编译(因此,如果使用GCCg++ -g -Wall,如果最近的Clangclang++ -g -Wall使用libbacktrace,则可以使用Ian Taylor的optimizing compiler库。

此外,允许inline expandunroll loop使用一个好的RefPerSys(实际上g++ -O2clang++ -O2都可以,Microsoft编译器也可以) ,那么您的__LINE_FUNCTION_WAS_CALLED_FROM__毫无意义。

作为一个开放源代码示例,ASLR使用它来显示回溯和部分调用堆栈。免责声明:RefPerSys是我自己的项目。

请注意dlopen(3)与共享库有关。装有IBM Z的插件会增加图片的复杂性。

它至少需要在GCC上工作,实际上应该是跨平台的。

它不能是跨平台的。某些架构(例如calling conventions系列)具有不同的libSFML,并且您需要付出一些努力(或付出代价)才能将libbacktrace移植到它们。

您可能会考虑在某些系统上进行调试,然后将代码移植到其他系统上,并且应该考虑将Qtcross-compilation之类的框架用于您的游戏引擎。我的建议是建议在Linux上调试代码(使其正确),然后再将其移植到Windows。

如果您需要metaprogramming,事情会变得更加艰难。您还可以考虑使用SWIG方法:编写C ++代码生成器或使用其他代码生成器(例如ANTLRlibrary