运行时不执行任何操作的函数有什么用处,即:
void Nothing() {}
Run Code Online (Sandbox Code Playgroud)
请注意,我不是在谈论等待一定时间的函数,例如sleep()
,只是需要编译器/解释器给出的时间。
dbu*_*ush 129
这样的函数作为回调函数可能是必要的。
假设您有一个如下所示的函数:
void do_something(int param1, char *param2, void (*callback)(void))
{
// do something with param1 and param2
callback();
}
Run Code Online (Sandbox Code Playgroud)
该函数接收一个指向随后调用的函数的指针。如果您不是特别需要使用此回调执行任何操作,则可以传递一个不执行任何操作的函数:
do_something(3, "test", Nothing);
Run Code Online (Sandbox Code Playgroud)
abe*_*nky 47
当我创建包含函数指针的表时,我确实使用空函数。
例如:
typedef int(*EventHandler_Proc_t)(int a, int b); // A function-pointer to be called to handle an event
struct
{
Event_t event_id;
EventHandler_Proc_t proc;
} EventTable[] = { // An array of Events, and Functions to be called when the event occurs
{ EventInitialize, InitializeFunction },
{ EventIncrement, IncrementFunction },
{ EventNOP, NothingFunction }, // Empty function is used here.
};
Run Code Online (Sandbox Code Playgroud)
在此示例表中,我可以放置NULL
,NothingFunction
并在调用之前检查是否.proc
为。NULL
但我认为在表中放置一个不执行任何操作的函数可以使代码更简单。
Jos*_*hua 37
是的。很多事情都希望有一个函数来通知发生的某些事情(回调)。不执行任何操作的函数是表达“我不关心这个”的好方法。
我不知道标准库中有任何示例,但许多构建在其之上的库都有事件的函数指针。
例如,glib 定义了一个回调“GLib.LogFunc(log_domain, log_level, message, *user_data)”来提供记录器。空函数将是您在禁用日志记录时提供的回调。
Dan*_*ins 31
一个用例可能是作为临时存根一种用例是在程序开发过程中
如果我正在进行一定量的自上而下的开发,那么我通常会设计一些函数原型,编写主函数,然后想要运行编译器以查看到目前为止是否有任何语法错误。为了使编译发生,我需要实现相关的函数,我将通过最初创建不执行任何操作的空“存根”来实现。一旦我通过了编译测试,我就可以继续一次充实一个功能。
我所教的Gaddis 教科书《Starting with C++: From Control Structures Through Objects》是这样描述它们的(第 6.16 节):
存根是一个虚拟函数,它被调用而不是它所代表的实际函数。它通常会显示一条测试消息,确认它已被调用,仅此而已。
Sha*_*ger 13
接受参数但不对其执行任何操作的函数可以与执行有用操作的函数配对使用,这样即使使用无操作函数,参数仍会被计算。这在日志记录场景中非常有用,在这种情况下,仍然必须对参数进行求值以验证表达式是否合法并确保发生任何重要的副作用,但日志记录本身并不是必需的。当编译时日志记录级别设置为不需要该特定日志语句的输出的级别时,预处理器可能会选择无操作函数。
Dav*_*lor 13
我记得,Lions' Commentary on UNIX 6th Edition 中有两个空函数,附有 Source Code,以及本世纪初重新发行的介绍,名为 Ritchie、Kernighan 和 Thompson,就在上面。
吞噬其参数并且不返回任何内容的函数实际上在 C 中无处不在,但没有显式写出,因为它几乎在每一行都隐式调用。在传统 C 语言中,此空函数最常见的用途是不可见地丢弃任何语句的值。但是,从 C89 开始,可以将其明确拼写为(void)
。lint
每当函数返回值被忽略而没有显式地将其传递给这个不返回任何内容的内置函数时,该工具就会发出抱怨。其背后的动机是试图阻止程序员默默地忽略错误条件,并且您仍然会遇到一些使用编码风格的旧程序,(void)printf("hello, world!\n");
.
这样的函数可用于:
Tre*_*tni 12
不执行任何操作的函数的另一个临时用途可能是存在一行来放置断点,例如,当您需要检查传递到新创建的函数的运行时值时,以便您可以更好地决定执行哪些操作您要放入其中的代码将需要访问。就我个人而言,我喜欢使用自分配,即i = i
当我需要这种断点时,但无操作函数可能也可以工作。
void MyBrandNewSpiffyFunction(TypeImNotFamiliarWith whoKnowsWhatThisVariableHas)
{
DoNothing(); // Yay! Now I can put in a breakpoint so I can see what data I'm receiving!
int i = 0;
i = i; // Another way to do nothing so I can set a breakpoint
}
Run Code Online (Sandbox Code Playgroud)
从语言律师的角度来看,不透明的函数调用插入了优化障碍。
例如:
int a = 0;
extern void e(void);
int b(void)
{
++a;
++a;
return a;
}
int c(void)
{
++a;
e();
++a;
return a;
}
int d(void)
{
++a;
asm(" ");
++a;
return a;
}
Run Code Online (Sandbox Code Playgroud)
++a
函数中的表达式可以b
合并到a += 2
,而在c
函数中,a
需要在函数调用之前更新并在之后从内存中重新加载,因为编译器无法证明e
没有访问,类似于函数中的a
(非标准)。asm(" ")
d
空函数在特定于平台的抽象层中并不罕见。通常有些功能只在某些平台上需要。例如,函数void native_to_big_endian(struct data* d)
在小端 CPU 上可能包含字节交换代码,但在大端 CPU 上可能完全为空。这有助于保持业务逻辑与平台无关且可读。我还看到过这样的任务,例如将本机文件路径转换为 Unix/Windows 风格、硬件初始化函数(当某些平台可以使用默认值运行而其他平台必须主动重新配置时)等。
归档时间: |
|
查看次数: |
11306 次 |
最近记录: |