代码之家  ›  专栏  ›  技术社区  ›  peachykeen

为什么在.h文件中定义的函数在.c文件中被重新定义?

  •  0
  • peachykeen  · 技术社区  · 5 年前

    我正在阅读linuxv3.19的PID名称空间实现和 pid_namespace.h pid_namespace.c . 例如,在 pid_namespace.h 定义如下:

    static inline struct pid_namespace *copy_pid_ns(unsigned long flags,
        struct user_namespace *user_ns, struct pid_namespace *ns)
    {
        if (flags & CLONE_NEWPID)
            ns = ERR_PTR(-EINVAL);
        return ns;
    }
    

    然后进来 pid_namespace.c copy_pid_ns

    struct pid_namespace *copy_pid_ns(unsigned long flags,
        struct user_namespace *user_ns, struct pid_namespace *old_ns)
    {
        if (!(flags & CLONE_NEWPID))
            return get_pid_ns(old_ns);
        if (task_active_pid_ns(current) != old_ns)
            return ERR_PTR(-EINVAL);
        return create_pid_namespace(user_ns, old_ns);
    }
    

    0 回复  |  直到 5 年前
        1
  •  0
  •   Community CDub    4 年前

    注意

    这个问题忽略了从源代码库中提取源代码的相关信息,因此下面的答案不适用于这些文件中的源代码。似乎这两个定义中最多有一个是根据生成选项选择的,因此它们不会同时用于同一个生成中。

    关于 static inline

    标题中的版本已标记 . 在本声明中, static copy_pid_ns 拥有 内部联动装置 ,这意味着这里的定义只适用于 复印件 inline 因为这个函数太小了,如果编译器在任何地方调用它,只是为它编写代码来代替调用,而不是实际对函数使用子程序调用指令,那就太好了。(技术上 内联 只是在这方面给编译器的一个建议。优秀的现代编译器通常会自行决定要内联哪些函数。)

    因为标题中的定义是 内联函数 ,其他翻译单位无法访问。另一个源文件中的定义具有 ,意味着 复印件 静止的 版本)。在其他翻译单元中的使用必须使用实际的子程序调用指令来调用此函数。

    复印件

        2
  •  4
  •   Tsyvarev    5 年前

    这两个定义对应于两个 不兼容配置

    1. copy_pid_ns include/linux/pid_namespace.h#L76 CONFIG_PID_NS 选项 (参见标题中的第68行)。

    2. kernel/pid_namespace.c 仅使用编译 启用 (可以从 kernel/Makefile

    1. (没有 )对应于正在启用的某些功能。在这种配置中,功能是 定义 在某些源文件中,该文件仅在启用功能的情况下编译。

    2. 另一个 宣言 是一个 定义 属于 static inline

        3
  •  0
  •   Mihail Maldzhanski    5 年前

    1. 静态内联。。。-> 就像私人限定词一样, 将直接替换此函数,而不是作为引用访问它
    2. 没有限定符->更像一个公共外部函数。如果将函数的用法定义为 外部 您应该编译包含函数实现的(*.c)文件,然后链接器将您对函数的调用解析为引用。
        4
  •  0
  •   Armen Michaeli    5 年前

    这不是重新定义。实现这里的意图的关键是 static inline 很少在没有的情况下使用 静止的 内联

    static inline 定义 pid_namespace.h 仅对直接或间接包含该头文件的翻译单元(.c文件)可见。这个 静止的 pid_命名空间.h 从另一个翻译单位,该翻译单位将有自己的,另一个副本的功能。每个对象文件都有其自己的函数定义副本,仅对其自身可用。另外,因为 is free to "inline" it .

    第二个定义没有 静止的

    在实践中,有很多方法可以使用。前一个定义可能是在内核模式下使用的简短版本(特权内核代码),而后一个定义在用户模式下使用,例如处理系统调用的结果。

    一般来说,只要链接器最多有一个对象可用,就允许多次定义过程(以防它需要解析对函数的引用,如函数调用)。你可以随心所欲地处理你的.c和.h文件,只要这个要求成立。如果你也知道如何使用 静止的 限定符,可以添加外部不可见的定义( 静止的 )并受益于编译器能够内联它们。