【问题标题】:How to concat __func__ and __LINE__ in a macro definition如何在宏定义中连接 __func__ 和 __LINE__
【发布时间】:2020-08-16 01:07:17
【问题描述】:

我想定义一个宏来连接__func__(或__FUNCTION__)和__LINE__

以下工作正常:

// macro_test.cc
#include <iostream>

#define STR2(X) #X
#define STR(X) STR2(X)
#define FILE_LOCATION __FILE__ ":" STR(__LINE__) " "

int main() {
  std::cout << FILE_LOCATION << "is <file_name>:<line_number>" << std::endl;
  return 0;
}

这是输出

$ ./a.out 
macro_test.cc:8 is <file_name>:<line_number>

但是下面给出了一个编译错误(我刚刚将__FILE__替换为__func__):

// macro_test.cc
#include <iostream>

#define STR2(X) #X
#define STR(X) STR2(X)
#define FUNC_LOCATION __func__ ":" STR(__LINE__) " "

int main() {
  std::cout << FUNC_LOCATION << "is <function_name>:<line_number>" << std::endl;
  return 0;
}

~$ gcc macro_test.cc 
macro_test.cc: In function ‘int main()’:
macro_test.cc:5:32: error: expected ‘;’ before string constant
 #define FUNC_LOCATION __func__ ":" STR(__LINE__) " "
                                ^
macro_test.cc:8:16: note: in expansion of macro ‘FUNC_LOCATION’
   std::cout << FUNC_LOCATION << "is <function_name>:<line_number>" << std::endl;

有人知道这是什么原因吗?我怎样才能做到这一点?

我在 Linux (Ubuntu 18.04) 上使用 gcc 5.4.0。

【问题讨论】:

  • STR(__func__) ?
  • @bolov 和 STR(__func__) 输出为:__func__:8 is &lt;function_name&gt;:&lt;line_number&gt;
  • #define FUNC_LOCATION [](auto fn, auto ln) { std::stringstream ss; ss &lt;&lt; fn &lt;&lt; ":" &lt;&lt; ln &lt;&lt; " "; return ss.str(); }(__func__, __LINE__)
  • @Eljay 在回答中怎么说?另一个答案说为什么 OP 提案不起作用但没有回答 OP 问题“如何做”

标签: c++ c gcc c-preprocessor


【解决方案1】:

给出一个编译错误 [...] 任何人都知道这是什么原因

__func__ 是一个变量:

static const char __func__[] = "function-name";

不是到(字符串)文字(例如__FILE__“扩展”。)

(文档在这里:https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html

【讨论】:

    【解决方案2】:

    您可以将立即调用的函数表达式(借用 JavaScript 术语)作为宏实现,而不是尝试将不兼容的类型拼接成单个字符串。

    由于它是立即执行的,所以我将两个预处理器标识符作为参数传入。

    它们不应该被烘焙到 lambda 的主体中,因为 __func__ 将反映 lambda 而不是调用 lambda 的例程。

    #include <sstream>
    #define FUNC_LOCATION \
        [](auto fn, auto ln) { \
            std::stringstream ss;
            ss << fn << ":" << ln << " "; \
            return ss.str(); \
        }(__func__, __LINE__)
    
    int main() {
        std::cout << FILE_LOCATION << "is <file_name>:<line_number>" << std::endl;
        return 0;
    }
    

    【讨论】:

    • 这可行,但我想会有与之相关的运行时成本。我正在寻找一个在编译时评估的纯宏(预处理器),因此没有运行时成本。猜猜这是不可能的。
    • @Curious • 制作C 字符串文字还有另一个成本,因为它们不同,所以它们无法合并。在我的项目中,我们能够通过摆脱 FILE+LINE 连接并使用两个参数来将可执行文件的大小减少 50 MB,这与我提供的类似。如今,50 MB 可能看起来并不多,但对于一个可下载的 iOS 或 Android 应用程序来说,这仍然是一个很大的足迹,没有明显的好处。 (如果没有分析来证明性能损失是显着的,我不会把任何股票放在“运行时成本”索赔中。)
    猜你喜欢
    • 2015-11-29
    • 1970-01-01
    • 2013-10-21
    • 1970-01-01
    • 2010-12-08
    • 2016-05-07
    相关资源
    最近更新 更多