在一次 C 面试中,我被问到一个非常有趣的问题:如何实现一个函数 f(),使其只能从特定的 g() 函数中调用。如果 g() 以外的函数尝试调用 f() 将导致编译器错误。
起初,我认为这可以通过函数指针来完成,并且我可以在运行时接近阻塞调用。但是我想不出编译时策略。我什至不知道这是否可以使用 ansi C.
有人有什么主意吗?
在一次 C 面试中,我被问到一个非常有趣的问题:如何实现一个函数 f(),使其只能从特定的 g() 函数中调用。如果 g() 以外的函数尝试调用 f() 将导致编译器错误。
起初,我认为这可以通过函数指针来完成,并且我可以在运行时接近阻塞调用。但是我想不出编译时策略。我什至不知道这是否可以使用 ansi C.
有人有什么主意吗?
这是一种方法:
int f_real_name(void)
{
...
}
#define f f_real_name
int g(void)
{
// call f()
}
#undef f
// calling f() now won't work
另一种方法,如果您可以保证f()
并且g()
是文件中唯一的函数,则将其声明f()
为static
.
编辑:另一个导致编译器错误的宏技巧:
static int f(void) // static works for other files
{
...
}
int g(void)
{
// call f()
}
#define f call function
// f() certainly produces compiler errors here
将 g() 和 f() 放在同一个模块中,并将 f() 声明为静态。static 关键字使 f() 仅可用于同一模块或源文件中的函数。
您可能还想提一下,在带有 f() 和 g() 的模块中不应允许使用其他方法,否则它们可能会调用 f()。
PS - 我真的认为 Chris Lutz 的回答实际上是最好的。它提到了这种方法,但也提到了一个巧妙的宏重命名,它适用于较少的环境条件(不需要专门用于这两个功能的模块文件)。
另请注意,使用宏,您可以执行以下操作:
#define f() f_should_not_be_called_by_anything_except_g
这会显示一个很好的错误消息,并且自动完成程序(如 Visual Studio)会在用户键入 f() 时显示该提示。
您可以使用以下static
关键字创建模块私有函数:
static void func(void)
{
// ...
}
然后,func()
只能由同一文件中定义的其他函数调用(技术上,相同的翻译单元:其定义包含在#include
指令中的其他函数仍然可以访问它)。 func
据说有内部联动。所有其他函数(即没有static
关键字)都被称为具有外部链接。
除此之外,不,没有办法使功能无法访问。您可以使用宏来更改函数的名称,但其他代码始终可以使用适当的名称访问它。
GCC 的一个选项是使用嵌套函数。虽然它不是标准的 C,但它工作得很好。
将f()
和g()
在同一个源文件中,声明为f()
静态的。
只有巧合才有可能。
如果函数 f() 和 g() 都在同一个源文件中,并且文件中没有其他函数,并且如果 g() 从未将指向 f() 的函数指针返回给它的任何调用者,则使 f () 静态将完成这项工作。
如果其他函数必须出现在同一个源文件中,将 f() 作为静态函数放在文件的底部,并且只在它之后立即定义 g() 会达到或多或少相同的效果 - 尽管如果你没有告诉编译器在“缺少声明”上生成错误,其他函数可以调用它并发出警告。
#include <stdio.h>
extern void g(void); /* in a header */
/* Other functions that may not call f() go here */
static void f(void)
{
puts("X");
}
void g(void)
{
f();
}
显然,这种技术不能可靠地扩展到同一文件中的另一对函数 - x() 和 y() - 这样 x() 并且只有 x() 可以调用 y() 而 g() 并且只有 g()可以同时调用 f()。
然而,通常你会依赖程序员的纪律,简单地在源文件中使 f() 成为静态,以及只有 g() 可以调用它的注释,然后对任何修改代码的人进行纪律处分,以便使用除g() 调用 f()。