如何使用atexit()注册非void函数?

eml*_*lai 13 c c++ ncurses atexit

我正在尝试注册一个函数,该函数返回一个int在程序结束时使用该atexit()函数调用的函数.(具体来说,endwin()来自ncurses 的功能.)

但由于atexit()需要一个指向void函数的指针,我遇到了一个问题.我尝试了以下方法:

static_cast<void (*)()>(endwin)
Run Code Online (Sandbox Code Playgroud)

但似乎不允许static_castint功能到void功能.

我想要完成的是什么,如果是的话,怎么样?

注意:我愿意忽略函数的返回值.


编辑:我也尝试创建一个lambda函数,它似乎做我想要的:

atexit([]{ endwin(); });
Run Code Online (Sandbox Code Playgroud)

与包装/转发功能相比,这是一个很好的解决方案吗?(除此之外,它需要C++ 11并避免定义一个新功能,其唯一目的只是转发另一个功能.)

Die*_*ühl 23

函数指针无法转换.只需注册转发功能:

#ifdef __cplusplus
extern "C"
#endif
void endwin_wrapper() { endwin(); }
...
atexit(endwin_wrapper);
Run Code Online (Sandbox Code Playgroud)

由于您标记了问题C++:如果您在C++中定义转发函数,则需要声明它是否extern "C"具有正确的语言链接.

  • C++中的`atexit()`有两个重载,其中一个是`extern'C++"int atexit(void(*f)(void))noexcept;`它带有一个C++链接函数指针.(另一个是`extern"C"int atexit(void(*f)(void))noexcept;`,取一个C连接函数指针.) (9认同)
  • @NicholasWilson:见:http://stackoverflow.com/questions/2594178/why-do-you-need-extern-c-for-c-callbacks-to-c-functions (2认同)

eml*_*lai 11

使用当前的C++标准,lambda可能是最好的解决方案:

atexit([]{ endwin(); });
Run Code Online (Sandbox Code Playgroud)

现在没有必要定义一个全新的命名函数,其唯一目的就是转发另一个函数.


如果您有一天决定需要在程序退出时调用更多函数,则可以使用以下新调用来定义它们atexit():

atexit(anotherCleanupFunction);
Run Code Online (Sandbox Code Playgroud)

或者,您可以将它们添加到lambda主体:

atexit([]{
  anotherCleanupFunction();
  endwin();
});
Run Code Online (Sandbox Code Playgroud)

但是,当您要注册多个函数时atexit(),用于保存所有这些函数的单独包装函数可能是更好的解决方案.但是没有一个正确的答案,只需编写好的和清晰的代码.(atexit()通过充满函数调用的lambda调用可能看起来很混乱.)


πάν*_*ῥεῖ 6

"我想要完成的是什么,如果是的话,怎么样?"

您只需编写自己的包装函数endwin()并注册该函数

void myEndwin() {
    endwin();
}
Run Code Online (Sandbox Code Playgroud)