C回调 - 可选参数?

时间:2017-06-12 10:13:42

标签: c callback

嘿,我已经在我的C程序中实现了一些回调。

typedef void (*server_end_callback_t)(void *callbackArg);

然后我有变量内部结构来存储这个回调

server->server_end_callback = on_sever_end; 

我注意到我可以传递on_server_end回调函数实现,跳过void *callbackArg并且代码正常工作(没有错误)。

跳过一些参数如void *实现回调函数原型采用这样的参数是否正确?

void on_server_end(void) { 
 // some code goes here
}

4 个答案:

答案 0 :(得分:2)

我认为从C的角度来看它是一种未定义的行为,但它的工作原理是因为你正在使用的调用约定。

例如,AMD64 ABI声明前六个参数使用CPU寄存器传递给调用函数,而不是堆栈。因此,调用者和被调用者都不需要对前六个参数进行清理,并且工作正常。

有关详细信息,请参阅the Wikipedia.

答案 1 :(得分:0)

由于传递参数的惯例,代码可以正常工作。调用者知道被调用者期望一些参数 - 恰好一个。因此,它准备参数(在寄存器或堆栈中 - 取决于您平台上的ABI)。然后被调用者是否使用这些参数。从被调用者返回后,调用者会在必要时清理堆栈。那是个谜。

但是,您不应通过传递不兼容的函数来滥用此特定行为。总是使用选项-W -Wall -Werror(clang / gcc和compatible)编译代码是一种很好的做法。启用此选项会为您提供编译错误。

答案 2 :(得分:0)

C允许使用函数参数快速和松散地进行一定数量的播放。所以

void (*fptr) ();

表示“指向带有零个或多个参数的函数的指针”。然而,这是为了向后兼容,在新的C代码中使用它并不明智。另一种方式

void (*fptr)(void *ptr)
{
   /* don't use the void */
}

/* in another scope */
 (*fptr)(); /* call with no arguments */

也可以,只要你不使用void *,我相信它可以保证工作虽然我不完全确定(在现代机器上,调用约定是传递第一个参数in寄存器,所以你只需要一个垃圾寄存器,它会工作)。再一次,依靠它是一个非常糟糕的主意。

您可以传递一个void *,然后将其转换为适当类型的结构,其中包含任意数量的参数。这是一个好主意,也是对C灵活性的合理使用。

答案 3 :(得分:0)

  

跳过一些像void *实现回调函数的参数是正确的,原型采用这样的参数吗?

不,不是。具有给定函数声明的任何函数都不与不同函数声明的函数兼容。此规则也适用于指向函数的指针。

因此,如果你有pthread_create(..., my_callback, ...);这样的函数,并且它希望你传递一个类型为void* (*) (void*)的函数指针,那么你就不能传递一个不同格式的函数指针。这会调用未定义的行为,编译器可能会生成错误的代码。

话虽这么说,函数指针兼容性是许多系统上常见的非标准扩展。如果系统的调用约定是以函数格式不重要的方式指定的,并且特定的编译器端口支持它,那么这样的代码可能正常工作。

然而,此类代码不可移植且不标准。最好尽可能避免使用它。