【问题标题】:GCC macro to print all function argumentsGCC 宏打印所有函数参数
【发布时间】:2021-11-17 21:42:46
【问题描述】:

我需要一些宏或其他方式来打印当前函数及其参数。对于函数名称,这很简单,因为我们可以使用例如__PRETTY_FUNCTION__。是否有一些包含函数参数的宏?或者您可以将va_list 和va_start 用于非可变函数吗?

类似于__VA_ARGS__ 的东西,但用于常规函数,而不是宏。只要它有效,我不介意将它从某些符号表等中取出。

要做这样的事情:

#define FUNC_ENTER printName(__PRETTY_FUNCTION__); printArgs(__WHAT_IM_MISSING__);

void someFunc(int a, int b)
{
    FUNC_ENTER;
    
    // ... rest of the function ...
}

void main()
{
    someFunc(5, 10);

    // Should print "Entering 'someFunc' with '5 10'" or something similar. 
}

P.S.1。我知道我可以通过编写 FUNC_ENTER(a, b) 来实现它 - 但我想省去自己输入参数的时间

附注 2。不要建议 GCC 的 __cyg_profile_func_enter - 因为我不希望 每个 函数都使用这个宏。

【问题讨论】:

  • 不,除非您将实际参数传递给宏,否则实际上不可能通用地创建类似的东西。
  • 问题是预处理器正在处理文本,而不是 C 代码。因此它不知道存在类似函数参数的东西。它甚至不知道宏在函数体内展开
  • 但是您可以使用 xmacro 将 both 扩展为函数参数和打印命令。虽然代码可能有点混淆
  • C 还是 C++? C++ 有一些 C 没有的技巧。所以区分很重要

标签: c++ c gcc macros profiling


【解决方案1】:

注意:以下都是 C++ 特有的。

我不知道在有问题的函数内部有一种干净的方法。但是你可以很容易地将它作为函数的 包装器,按照以下一般顺序:

#include <iostream>

// just a couple functions with different number/types of arguments
// to demonstrate invoking
int someFunc(int a, int b) { 
    return a + b;
}

void otherFunc(std::string const &a, int b, long long c) { 
    std::cout << "a: " << a << ", b: " << b << ", c: " << c;
}

// Print out arguments, then invoke function:
template <class F, typename ...Args>
auto invoke(F f, Args && ...args) {
    (std::cout << "Args: " << ... << args) << "\n";
    return f(std::forward<Args>(args)...);
}

int main() { 
    std::cout << invoke(someFunc, 1, 2) << "\n";
    invoke(otherFunc, "first", 2, 3);
    std::cout << "\n";
}

如果你想对用户“隐藏”实现,这样他们只需要调用一个看起来很普通的函数,你可以很容易地为每个单独的函数添加一个小包装器,沿着这条线:

namespace {
// this is the actual implementation, hidden from the user
void function_implementation(/* whatever args*/) { 
    // ...
}
}

// this is all the user sees--print args, then invoke implementation.
// For each wrapper, you edit the name you want the user to see, and the 
// implementation it invokes.
template <typename ...Args>
void function(Args && ...args) {
    std::cout << __PRETTY_FUNCTION__;
    invoke(function_implementation, std::forward<Args>(args)...);
}

正如这段代码所代表的,它有一个小困难:它不会在每个参数之间插入分隔符,因为它正在打印它们。如果需要,您可以(对于一种可能性)递归地扩展参数包,而不是使用折叠表达式:

template <class T>
void print(T const &t) {
    std::cout << t << "\t";
}

template<typename T, typename... Args>
void print(T n, Args ... args) {
    print(n);
    print(args...);
    std::cout << "\n";
}

template <class F, typename ...Args>
auto invoke(F f, Args && ...args) {
    print(std::forward<Args>(args)...);
    return f(std::forward<Args>(args)...);
}

【讨论】:

  • 感谢您的代码,尽管不幸的是它完全不切实际。我打算用它来跟踪函数调用。我不能到处使用 invoke() 污染代码,也不能为我想要跟踪的每个函数编写包装器。那是数百个......我想我会明确地将参数传递给我的打印,比如FUNC_ENTER(a, b)。不过还是谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-08
  • 2014-08-14
  • 1970-01-01
  • 1970-01-01
  • 2015-10-29
  • 1970-01-01
  • 2017-08-23
相关资源
最近更新 更多