简体   繁体   English

C函数指针-删除参数时会发生什么?

[英]C Function Pointers - What happens when you drop an argument?

all. 所有。 I'm currently working with an old established code base for a new project which is basically undocumented (ie averages 1 one-line comment per file). 我目前正在使用一个旧的已建立代码库的新项目,而该项目基本上没有文档记录(即每个文件平均1条单行注释)。 I just ran into something which I haven't seen before and am not quite sure how to interpret. 我遇到了我以前从未见过的东西,并且不确定如何解释。

Firstly, they define a function type and a function in the header file (.h) in the form: 首先,它们在头文件(.h)中以以下形式定义函数类型和函数:


typedef void (*SOME_FUNCTION)(void *data, EXECUTION_CONTEXT *ec);
void add_function(SOME_FUNCTION aFunction, void *data);

In the main source file (.c), there is a function defined: 在主源文件(.c)中,定义了一个函数:


void add_function(void (*f)(void *data), void *data) 
{
   (Some code here)
}

So okay, there's a function pointer... but what the heck happened to the second argument, ec? 好的,有一个函数指针...但是第二个参数ec到底发生了什么? Why would someone use a code design like this? 为什么有人会使用这样的代码设计? For reference, when the function add_function is used, it is used in this sort of form: 作为参考,当使用函数add_function时,它以以下形式使用:


void passedFunction(void *data, EXECUTION_CONTEXT *ec) 
{
    (Stuff the function does.)
}

void CallingFunction()
{
    data = (some data stuff);
    add_function((SOME_FUNCTION)passedFunction, data);
}

So, as you can see, the passed functions use the correct form that fits the original SOME_FUNCTION argument signature, but the definition for the add_function arguments is short by one argument. 因此,如您所见,传递的函数使用适合原始SOME_FUNCTION参数签名的正确形式,但是add_function参数的定义只有一个参数短。

Formally, the results are undefined: you are only permitted to call a function via a function pointer if the types match. 形式上,结果是不确定的:如果类型匹配,则只能通过函数指针调用函数。

As for what actually happens, it depends on the calling convention and what the function does with the arguments. 至于实际发生的情况,这取决于调用约定以及函数对参数的作用。 Chances are, the results aren't going to be good. 很有可能结果并不理想。

To add on James' answer: 要补充詹姆斯的答案:

Since the default calling convention is most likely cdecl , the call site is responsible for cleaning up the stack after passedFunction returns. 由于默认的调用约定很可能是cdecl ,所以调用站点负责在passedFunction返回之后清理堆栈。 Since the call site knows that it passed just 1 argument to the callee, the compiler can clean up the stack normally (even though technically this is undefined behavior). 由于调用站点知道它仅向被调用方传递了1个参数,因此编译器可以正常清理堆栈(即使从技术上讲这是未定义的行为)。

Change the calling convention on passedFunction to stdcall though, and you 're in for some fireworks. 但是,将passedFunction上的调用约定更改为stdcall ,您将参加一些烟花大会。

From the example code below, it doesn't appear that the variable(s) that are defined in the function pointer matters during the check. 在下面的示例代码中,在检查过程中似乎没有函数指针中定义的变量重要。 The code below compiles without warning. 下面的代码无需警告即可编译。

#include <stdio.h>

int temp(int (*m)());

int main(int argc, char *argv[]) {
        return temp(main);
}

int temp(int (*m)()) {
        return 1;
}

However, the code below throws an error. 但是,下面的代码将引发错误。

#include <stdio.h>

int temp(void (*m)());

int main(int argc, char *argv[]) {
        return temp(main);
}

int temp(void (*m)()) {
        return 1;
}

Due to this; 由于这个; it seems that the compiler (at least in my case GCC) only cares what the return value of the function pointer will be. 似乎编译器(至少在我的情况下为GCC)仅关心函数指针的返回值。 The interesting thing here is that you CAN send the parameters correctly but if you do NOT specify the parameter (in our example m()), then the variables in m() when called will be junk. 有趣的是,您可以正确发送参数,但是如果未指定参数(在我们的示例m()中),则调用m()中的变量将是垃圾。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM