为什么像 nginx 和 LuaJIT 这样的一些 C 项目会在所有代码文件、函数和数据类型前加上项目名称?
Why do some C projects like nginx and LuaJIT prefix all their code files, functions and data types with the project's name?
查看 nginx 的代码,我发现几乎所有内容都以 ngx_
.
为前缀
文件:
ngx_list.c
ngx_list.h
ngx_log.c
ngx_log.h
代码:
ngx_log_t *ngx_log_init(u_char *prefix);
void ngx_cdecl ngx_log_abort(ngx_err_t err, const char *fmt, ...);
void ngx_cdecl ngx_log_stderr(ngx_err_t err, const char *fmt, ...);
LuaJIT 与 lj_
.
几乎相同
文件:
lj_alloc.c
lj_alloc.h
lj_api.c
lj_arch.h
代码:
LJ_ASMF void LJ_FASTCALL lj_vm_ffi_call(CCallState *cc);
LJ_FUNC CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o);
LJ_FUNC int lj_ccall_func(lua_State *L, GCcdata *cd);
其他项目做同样的事情,这只是我想到的两个。他们为什么这样做呢?如果它是项目的 public API 我会得到它,因为它将暴露给第三方代码。但是我复制的代码是(私有)实现的一部分,所以为什么要命名它?
我怀疑没有绝对的理由。我怀疑这只是人们(某些人)感觉更舒服的事情。我自己不会这样做,但我想我可以看到它的吸引力。
例如,我有一个多精度算术库,我有一天为了好玩而写的。它具有 mp_add()
、mt_sub()
等函数。这些函数的源代码位于文件 add.c
和 sub.c
.
中
现在,由于该库的所有源代码都位于名为 mp
的子目录中,因此我从来没有想过给文件起 mp_add.c
或 mp_sub.c
这样的名称。那将是多余的:这些名称已经具有非常真实的意义 mp/add.c
、mp/sub.c
等
但我不得不承认,使用名为 add.c
的文件来检查我的 multiprecision 添加代码确实感觉有点奇怪。它不是整数加法代码,也不是定点或有理数加法代码,也不是通用加法代码。它是非常具体的多精度加法代码,其中定义的函数都具有 mp_
前缀。那么文件名不应该也有那个前缀吗?
正如我所说,不,最后我不会(我没有)给它那个前缀。但正如我也说过的,我想我可以看到吸引力。
附录:上面我回答了关于文件名的问题,但你也问了关于内部——"private"——函数名的问题。而那些是不同的;那些肯定需要一个前缀,至少在 C 中是这样。
问题是 C 实际上没有任何命名空间机制。因此,您几乎总是必须在所有全局符号上使用特定于项目的前缀来伪造它。
考虑函数 ngx_log_abort()
。它是 nginx 私有的;客户端代码不会调用它。但它是一个全局函数,所以如果它只是命名为 log_abort
,则很有可能与客户端代码(或其他一些库代码)中也命名为 [=] 的完全不同的函数发生冲突22=].
你可能会问,那为什么ngx_log_abort
是一个全局函数呢?当然答案是组成 nginx 库的任何函数都可能需要调用它,所以它几乎必须是全局的。
您可能会问,那为什么 ngx_log_abort
不是文件范围的 static
函数?答案是,如果 如果 整个 nginx 库的所有源代码都限制在一个 C 源文件中 nginx.c
,那将是可行的。但作者可能不想那样限制自己。
如果您想用 C 编写封装良好的库,您的 "private" 函数有两种选择:
将它们设为文件范围 static
,并限制自己对大部分或所有库使用单个源文件。
使它们真正成为全球性的,但带有唯一前缀。也不要将它们的声明放在 public 头文件中。 (这样客户就不能在不作弊的情况下给他们打电话。)
在其他语言中,您有其他隐藏私有符号的机制,但在 C 中没有。
查看 nginx 的代码,我发现几乎所有内容都以 ngx_
.
文件:
ngx_list.c
ngx_list.h
ngx_log.c
ngx_log.h
代码:
ngx_log_t *ngx_log_init(u_char *prefix);
void ngx_cdecl ngx_log_abort(ngx_err_t err, const char *fmt, ...);
void ngx_cdecl ngx_log_stderr(ngx_err_t err, const char *fmt, ...);
LuaJIT 与 lj_
.
文件:
lj_alloc.c
lj_alloc.h
lj_api.c
lj_arch.h
代码:
LJ_ASMF void LJ_FASTCALL lj_vm_ffi_call(CCallState *cc);
LJ_FUNC CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o);
LJ_FUNC int lj_ccall_func(lua_State *L, GCcdata *cd);
其他项目做同样的事情,这只是我想到的两个。他们为什么这样做呢?如果它是项目的 public API 我会得到它,因为它将暴露给第三方代码。但是我复制的代码是(私有)实现的一部分,所以为什么要命名它?
我怀疑没有绝对的理由。我怀疑这只是人们(某些人)感觉更舒服的事情。我自己不会这样做,但我想我可以看到它的吸引力。
例如,我有一个多精度算术库,我有一天为了好玩而写的。它具有 mp_add()
、mt_sub()
等函数。这些函数的源代码位于文件 add.c
和 sub.c
.
现在,由于该库的所有源代码都位于名为 mp
的子目录中,因此我从来没有想过给文件起 mp_add.c
或 mp_sub.c
这样的名称。那将是多余的:这些名称已经具有非常真实的意义 mp/add.c
、mp/sub.c
等
但我不得不承认,使用名为 add.c
的文件来检查我的 multiprecision 添加代码确实感觉有点奇怪。它不是整数加法代码,也不是定点或有理数加法代码,也不是通用加法代码。它是非常具体的多精度加法代码,其中定义的函数都具有 mp_
前缀。那么文件名不应该也有那个前缀吗?
正如我所说,不,最后我不会(我没有)给它那个前缀。但正如我也说过的,我想我可以看到吸引力。
附录:上面我回答了关于文件名的问题,但你也问了关于内部——"private"——函数名的问题。而那些是不同的;那些肯定需要一个前缀,至少在 C 中是这样。
问题是 C 实际上没有任何命名空间机制。因此,您几乎总是必须在所有全局符号上使用特定于项目的前缀来伪造它。
考虑函数 ngx_log_abort()
。它是 nginx 私有的;客户端代码不会调用它。但它是一个全局函数,所以如果它只是命名为 log_abort
,则很有可能与客户端代码(或其他一些库代码)中也命名为 [=] 的完全不同的函数发生冲突22=].
你可能会问,那为什么ngx_log_abort
是一个全局函数呢?当然答案是组成 nginx 库的任何函数都可能需要调用它,所以它几乎必须是全局的。
您可能会问,那为什么 ngx_log_abort
不是文件范围的 static
函数?答案是,如果 如果 整个 nginx 库的所有源代码都限制在一个 C 源文件中 nginx.c
,那将是可行的。但作者可能不想那样限制自己。
如果您想用 C 编写封装良好的库,您的 "private" 函数有两种选择:
将它们设为文件范围
static
,并限制自己对大部分或所有库使用单个源文件。使它们真正成为全球性的,但带有唯一前缀。也不要将它们的声明放在 public 头文件中。 (这样客户就不能在不作弊的情况下给他们打电话。)
在其他语言中,您有其他隐藏私有符号的机制,但在 C 中没有。