如何将参数传递给在 atexit() 内部的函数,C

huangapple go评论73阅读模式
英文:

How to pass arguments to the function inside atexit(), C

问题

void UNREG_on_exit(COT_arguments args, Node_Information *node) {
    // Your function implementation here
}

// Option 1
atexit(UNREG_on_exit);

// Option 2
atexit((void (*)(void)) {UNREG_on_exit, args, &node});
英文:

I have this function that does some free and unregs from a network:

void UNREG_on_exit(COT_arguments args, Node_Information *node)

I'm trying to make it be called whenever I'm exiting the program (even with Ctrl+C)

The problem is how do I pass the arguments?
Never done a function pointer and can't really find an answer.

Currently I have:

void UNREG_on_exit(args, &node); // This is how you make the pointer?
atexit(UNREG_on_exit);

// or //

atexit((void) {
    UNREG_on_exit(args, &node); // Or like this?
});

I have no idea, and both of them give me an error.

"expected an identifier", a red line under the argument

Addicional Info:

typedef struct Node_Information
{
    int id;
    int net;
    Backup bck;
    Extern ext;
    Intern *intern_list;
    int InNetword;
    int debug_mode;
    int IsREGED;
    int fd;
    Table *table_list;
    StringList *contents_list;
    PendingConnections *pending_connections_list;
    QueryList *query_list;

} Node_Information;

typedef struct COT_arguments
{
    char *IP;
    int TCP;
    char *reg_IP;
    int reg_UDP;
} COT_arguments;

答案1

得分: 6

atexit注册的函数不能带参数。其签名必须是void (*)(void),即一个不返回任何内容且不带参数的函数。

您需要使用在程序的其他地方设置的全局变量,以便函数可以使用。

英文:

A function registered by atexit cannot take parameters. It's signature is required to be void (*)(void), i.e. a function that returns nothing and takes no parameters.

You'll need to use global variables that get set elsewhere in your program that the function can use.

答案2

得分: 4

atexit 不支持带参数的函数,因此您既不能向其注册这样的函数,也不能向该函数传递任何参数。您必须传递一个类型为 void(*)(void) 的函数指针——不带参数,不返回值。

因此,必须通过其他方式处理这部分内容,例如使用文件范围变量。与任何类似的“回调函数”使用一样,务必小心不要使用任何指向本地数据的指针,而只能使用静态存储或动态分配的内存。

还请注意,atexit 按照先进先出(FIFO)的顺序调用函数——即,最后注册的函数将首先执行。

示例:

#include <stdlib.h>
#include <stdio.h>

static char* str1;
static char* str2;

void this_is_the_end1(void) { puts(str1); }
void this_is_the_end2(void) { puts(str2); }

int main(void)
{
  str1 = "The end of everything that stands";
  atexit(this_is_the_end1);
  str2 = "The end of our elaborate plans";
  atexit(this_is_the_end2);

  puts("This is the end, beautiful friend");
  puts("This is the end, my only friend");
}

输出顺序由ISO C保证:

This is the end, beautiful friend
This is the end, my only friend
The end of our elaborate plans
The end of everything that stands
英文:

atexit doesn't support functions taking parameters, so you can neither register such a function with it nor pass any parameters to that function. You have to pass a function pointer of type void(*)(void) - taking no parameters, returning no value.

So that part has to be handled through some other means, for example by using a file scope variable. As with any use of "callback functions" like this, be careful to not use any pointers to local data, but only to static storage or dynamically allocated memory.

Also note that atexit calls functions in reverse order like a FIFO - that is, the function registred last will get executed first.

Example:

#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

static char* str1;
static char* str2;

void this_is_the_end1 (void) { puts(str1); }
void this_is_the_end2 (void) { puts(str2); }

int main (void)
{
  str1 = &quot;The end of everything that stands&quot;;
  atexit(this_is_the_end1);
  str2 = &quot;The end of our elaborate plans&quot;;
  atexit(this_is_the_end2);

  puts(&quot;This is the end, beautiful friend&quot;);
  puts(&quot;This is the end, my only friend&quot;);
}

Output order is guaranteed by ISO C:

This is the end, beautiful friend
This is the end, my only friend
The end of our elaborate plans
The end of everything that stands

答案3

得分: 3

I have this function that does some free and unregs from a network:

void UNREG_on_exit(COT_arguments args, Node_Information *node)

I'm trying to make it be called whenever I'm exiting the program (even with Ctrl+C)

Frame challenge: why?

Especially why worry about freeing allocated memory at program exit, as the system will release that whether you explicitly free it or not. It will also close the process's open files, including network connections. That may not yield a clean application-level disconnect from remote network services, but any such services need to be robust against such events anyway.

I've written a lot of software, and I don't recall ever registering an exit handler. I arrange for resources to be cleaned up at appropriate points as the program progresses, and for any final cleanup to be performed explicitly at normal termination. This is clearer and less mysterious than using exit handlers. I rarely see a need to make special provisions to handle abnormal termination, and it is not possible to handle all abnormal terminations. Even if there were not fatal signals that cannot be caught or handled, there is no software-level protection available from abrupt power loss or catastrophic hardware failure.

But if you insist on trying to handle abnormal termination, then you're going to need to work harder. The exit handlers registered by standard atexit() and GNU-specific on_exit() run at normal program termination, which means when the exit() function is called or the initial call to main() returns. They do not run when the process is killed by a signal (which is the kind of termination Ctrl+C produces), or when it terminates because of a call to _exit() or _Exit(), or when it stops running without terminating, such as by calling execve().

You can probably avoid calling _Exit() and other problematic functions, but to engage cleanup upon receiving a signal, you will need to register a signal handler for all the signals whose default disposition is to terminate the program. Or for those that can be caught at all, at least, which is not all of them. Moreover, signal handlers may call only async-signal-safe functions, lest they introduce undefined behavior. I'm not sure what your "unregs" entail, so perhaps these would be ok, but free() is not async-signal-safe. Nor is exit(), lest you think you could call that to convert abnormal termination into normal termination.

As for the specifics of using atexit() to handle the normal-termination case, the signature of atexit() is:

int atexit(void (*function)(void));

The function-pointer argument is thus expected to point to a function that has no parameters and does not return anything, and that's how it will be called. Any data that such a function works on must be either globally scoped (global variables, environment variables, the process's own PID, ...) or discoverable by that function (time of day, files in some well-known directory, ...). Example:

static void *allocated;

static void cleanup_handler(void) {
    free(allocated);
}

int main(void) {
    at_exit(cleanup_handler);
    // ...
}

Your particular C implementation may provide other alternatives, such as the GNU-specific on_exit(). Details of these will vary. on_exit() itself permits you to register a data pointer along with the callback pointer, to be passed to the function when it is called. This is how you would provide data to that function, but note that the data must have static storage duration, else its lifetime will have already ended when the exit handler is called. Example:

struct data_to_clean_up {
    void *allocated;
    // ...
} loose_ends;

void cleanup_handler(int status, void *data) {
    struct data_to_clean_up *loose_ends = (struct data_to_clean_up *) data;
    free(loose_ends->allocated);
    // ...
}

int main(void) {
    on_exit(cleanup_handler, &loose_ends);

    // ...
}
英文:

> I have this function that does some free and unregs from a network:
>
> void UNREG_on_exit(COT_arguments args, Node_Information *node)
>
> I'm trying to make it be called whenever I'm exiting the program (even with Ctrl+C)

Frame challenge: why?

Especially why worry about freeing allocated memory at program exit, as the system will release that whether you explicitly free it or not. It will also close the process's open files, including network connections. That may not yield a clean application-level disconnect from remote network services, but any such services need to be robust against such events anyway.

I've written a lot of software, and I don't recall ever registering an exit handler. I arrange for resources to be cleaned up at appropriate points as the program progresses, and for any final cleanup to be performed explicitly at normal termination. This is clearer and less mysterious than using exit handlers. I rarely see a need to make special provisions to handle abnormal termination, and it is not possible to handle all abnormal terminations. Even if there were not fatal signals that cannot be caught or handled, there is no software-level protection available from abrupt power loss or catastrophic hardware failure.

But if you insist on trying to handle abnormal termination, then you're going to need to work harder. The exit handlers registered by standard atexit() and GNU-specific on_exit() run at normal program termination, which means when the exit() function is called or the initial call to main() returns. They do not run when the process is killed by a signal (which is the kind of termnination Ctrl+C produces), or when it terminates because of a call to _exit() or _Exit(), or when it stops running without terminating, such as by calling execve().

You can probably avoid calling _Exit() and other problematic functions, but to engage cleanup upon receiving a signal, you will need to register a signal handler for all the signals whose default disposition is to terminate the program. Or for those that can be caught at all, at least, which is not all of them. Moreover, signal handlers may call only async-signal-safe functions, lest they introduce undefined behavior. I'm not sure what your "unregs" entail, so perhaps these would be ok, but free() is not async-signal-safe. Nor is exit(), lest you think you could call that to convert abnormal termination into normal termination.

As for the specifics of using atexit() to handle the normal-termination case, the signature of atexit() is

int atexit(void (*function)(void));

The function-pointer argument is thus expected to point to a function that has no parameters and does not return anything, and that's how it will be called. Any data that such a function works on must be either globally scoped (global variables, environment variables, the process's own PID, ...) or discoverable by that function (time of day, files in some well-known directory, ...). Example:

static void *allocated;

static void cleanup_handler(void) {
    free(allocated);
}

int main(void) {
    at_exit(cleanup_handler);
    // ...
}

Your particular C implementation may provide other alternatives, such as the GNU-specific on_exit(). Details of these will vary. on_exit() itself permits you to register a data pointer along with the callback pointer, to be passed to the function when it is called. This is how you would provide data to that function, but note that the data must have static storage duration, else its lifetime will have already ended when the exit handler is called. Example:

struct data_to_clean_up {
    void *allocated;
    // ...
} loose_ends;

void cleanup_handler(int status, void *data) {
    struct data_to_clean_up *loose_ends = (struct data_to_clean_up *) data;
    free(loose_ends-&gt;allocated);
    // ...
}

int main(void) {
    on_exit(cleanup_handler, &amp;loose_ends);

    // ...
}

答案4

得分: 2

on_exit(3) 是你在寻找的内容。

英文:

on_exit(3) is what you are looking for.

huangapple
  • 本文由 发表于 2023年3月31日 22:02:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/75899424.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定