宏中未使用的参数会怎样?

Posted

技术标签:

【中文标题】宏中未使用的参数会怎样?【英文标题】:What happens to unused parameters in macro? 【发布时间】:2017-09-29 05:05:15 【问题描述】:

这个问题来自阅读内核,更具体地说是跟踪宏。我在研究内核模块如何执行二进制、elf 和脚本文件 (fs/exec.c) 时接触到它们。

由于某种原因,我不记得 tracepoint.h 文件是哪个文件,其中定义了宏 TRACE_EVENT 等。我使用 trace_event 作为示例,因为内核中的跟踪示例使用此宏。该示例使用了宏

    TRACE_EVENT(foo_bar,

    TP_PROTO(const char *foo, int bar, const int *lst,
         const char *string, const struct cpumask *mask),

    TP_ARGS(foo, bar, lst, string, mask),

    TP_STRUCT__entry(
        __array(    char,   foo,    10      )
        __field(    int,    bar         )
        __dynamic_array(int,    list,   __length_of(lst))
        __string(   str,    string          )
        __bitmask(  cpus,   num_possible_cpus() )
    ),

    TP_fast_assign(
        strlcpy(__entry->foo, foo, 10);
        __entry->bar    = bar;
        memcpy(__get_dynamic_array(list), lst,
               __length_of(lst) * sizeof(int));
        __assign_str(str, string);
        __assign_bitmask(cpus, cpumask_bits(mask), num_possible_cpus());
    ),

    TP_printk("foo %s %d %s %s %s %s (%s)", __entry->foo, __entry->bar,
/*
 * Notice here the use of some helper functions. This includes:
 *
 *  __print_symbolic( variable,  value, "string" , ... ),
 *
 *    The variable is tested against each value of the   pair. If
 *    the variable matches one of the values, then it will print the
 *    string in that pair. If non are matched, it returns a string
 *    version of the number (if __entry->bar == 7 then "7" is returned).
 */
          __print_symbolic(__entry->bar,
                    0, "zero" ,
                    TRACE_SAMPLE_FOO, "TWO" ,
                    TRACE_SAMPLE_BAR, "FOUR" ,
                    TRACE_SAMPLE_ZOO, "EIGHT" ,
                    10, "TEN" 
              ),

/*
 *  __print_flags( variable, "delim",  value, "flag" , ... ),
 *
 *    This is similar to __print_symbolic, except that it tests the bits
 *    of the value. If ((FLAG & variable) == FLAG) then the string is
 *    printed. If more than one flag matches, then each one that does is
 *    also printed with delim in between them.
 *    If not all bits are accounted for, then the not found bits will be
 *    added in hex format: 0x506 will show BIT2|BIT4|0x500
 */
          __print_flags(__entry->bar, "|",
                 1, "BIT1" ,
                 2, "BIT2" ,
                 4, "BIT3" ,
                 8, "BIT4" 
              ),
/*
 *  __print_array( array, len, element_size )
 *
 *    This prints out the array that is defined by __array in a nice format.
 */
          __print_array(__get_dynamic_array(list),
                __get_dynamic_array_len(list) / sizeof(int),
                sizeof(int)),
          __get_str(str), __get_bitmask(cpus))
);

所以,很自然地,在这之后我去了 TRACE_EVENT 的定义并找到了这个

#define TRACE_EVENT(name, proto, args, struct, assign, print) \ DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))

如您所见,trace_event 宏不使用 print 参数(或参数?),以及 struct 和 assign 参数。

非常清楚地表明宏需要它们,但在它下面只是调用不需要它们的 declare_trace 宏。

至于宏扩展的其余部分,我可以接受,没有什么意外,但是宏的这种特殊用法让我感到困惑。所有其他领域是否有某种目的,或者它们只是......没有任何存在的理由?

【问题讨论】:

未使用的参数没有任何反应;他们被忽略了。通常,存在(或有时曾经是)使用额外参数的宏的替代实现。如果绝对不需要额外的参数,您可以在调用宏时为未使用的参数使用 0(void)0 或一些此类占位符值。 我是这么认为的。我确定我快疯了,为什么有 3 个未使用的参数?我相信我忘记了什么。他们在这些参数上非常小心,所以他们必须在某个地方使用,或者我认为 跟踪系统是某种黑暗的 cpp 魔法,看看lxr.free-electrons.com/ident?i=TRACE_EVENT 并注意它被重新定义了。您可能需要深入研究文档才能了解其工作原理。 @pvg well sh*t ...但我知道它使用的是我显示的那个,因为它是跟踪点的直接示例,它也只包括 linux/tracepoint.h,这是我得到了一切..你可以检查文件 trace-event-sample.c 和 trace-event-sample.h @morcillo 恐怕我对此知之甚少。我认为这些示例文件最终被删除了。 【参考方案1】:

正如正确的@pvg 点,linux/tracepoint.h 只是跟踪点的冰山一角。此标头仅声明适当的功能和类型。这就是为什么它不处理 TRACE_EVENT 的一些参数。

但是带有跟踪定义的标头被处理了两次(甚至更多次),并且下次处理TRACE_EVENT 的所有参数。

有关 Linux 内核中的跟踪点的更多信息,请参阅Documentation/trace/tracepoints.txt。

【讨论】:

以上是关于宏中未使用的参数会怎样?的主要内容,如果未能解决你的问题,请参考以下文章

在 Freemarker 宏中模拟空参数

Confluence 6 在你用户宏中使用参数

Confluence 6 在你用户宏中使用参数

可变宏中令牌的连接

是否可以迭代可变参数宏中的参数?

在指向另一个宏的可变参数宏中为每个参数添加前缀