【问题标题】:Make function visible only within a library, not in API使函数仅在库中可见,而不在 API 中可见
【发布时间】:2025-12-19 06:25:11
【问题描述】:

我正在编写一个分布在多个文件中的 C99 库,例如

// core.h
void my_private_fn();

void API_my_public_fn();
// core.c
#include "core.h"

void my_private_fn() {
    do_something();
}

void API_my_public_fn() {
    do_something_else();
}
// module_a.h
#include "core.h"

void API_useful_thing();
// module_a.c
#include "module_a.h"

void API_useful_thing() {
    my_private_fn();
}

我只希望使用该库的程序可以看到带有API_ 前缀的函数,但我还需要在core.h 中公开my_private_fn 以便module_a.c 使用。 C 中有没有办法让my_private_fn 只在库中可见?

【问题讨论】:

  • 根据您使用的平台,您可以查看this answer(请注意,该问题的已接受答案并不能解决您的问题)。
  • 您可能需要查看 Windows 及其 __declspec(dllimport)__declspec(dllexport) 限定符,也许您需要查看 GNU ld Linker Scripts

标签: c visibility


【解决方案1】:

我找到了一种更简洁的方法来根据我选择的 Serge 的答案来布置我的代码,而他的最大优点就是。

关键是将“私有”函数放在只包含在 C 文件中的头文件中,而不是放在头文件中。这样,“私有”符号在内部可用,但对外部调用者不可用。一个完整的例子:

core.h:

void my_public_fn();

core_priv.h:

void my_private_fn();

core.c:

#include <stdio.h>

#include "core.h"
#include "core_priv.h"

void my_private_fn() {
    printf("Private function called.\n");
}

void my_public_fn() {
    printf("Public function called.\n");
}

module_a.h:

#include "core.h"

void module_a_fn();

module_a.c:

#include "core_priv.h"
#include "module_a.h"

void module_a_fn() {
    my_private_fn();
    my_public_fn();
}

如果我们愿意,我们可以将多个模块分组到一个公共库头中。

library.h:

#include "module_a.h"
// etc.

这样,使用该库的程序只需要包含一个文件,其中只有:

main.c:

#include "library.h"

int main() {
    //my_private_fn(); // This triggers a compile warning.
    my_public_fn();    // I can still reach the "core" public function.
    module_a_fn();     // This calls the "private" function internally.

    return 0;
}

使用gcc -Wall *.c -o main.o 编译并执行./main.o 产生:

Public function called.
Private function called.
Public function called.

【讨论】:

    【解决方案2】:

    如果函数必须只在定义它的编译单元中可见,那么您可以声明它static。因为 C 语言提供的可能作用域很少:一个符号只能有 3 个作用域:

    • 块本地(块可以是函数或函数内的块)
    • 静态作用域(函数外的静态声明):符号仅在声明它的编译单元中可见
    • 全局范围(函数外的非静态声明):符号在整个程序中可见。

    至多,您可以隐藏在官方文档 API 中未声明的私有包含文件中的声明。这样听话的用户就不应该使用它。但是你不能阻止用户将声明放在自己的代码中并使用函数。

    【讨论】:

    • 我喜欢这个,因为它不需要编译器特定的选项。我不关心流氓演员,只关心 API 的可读性。这比我建议的命名约定要好。谢谢。
    【解决方案3】:

    将它们放在一个内部头文件中,该文件只在库内部使用,不分发给最终用户,例如core_internal.h

    【讨论】: