【问题标题】:Defining a function through a pointer通过指针定义函数
【发布时间】:2021-11-02 08:37:21
【问题描述】:

我有以下代码:

typedef void (*func_type)(int a, int b);
func_type func;

int main()
{
   func = (func_type)GetProcAddress(NULL, "func");
}

此代码运行良好,但我想将func_type func; 更改为void func(int a, int b);(因为在键入参数时代码完成显示“func_type”而不是“func”)。 但是当我试图改变它时,编译器告诉我在主函数中“表达式必须是一个可修改的左值”。我试图在网上查找,但没有找到我的问题的答案。 代码变成这样:

typedef void (*func_type)(int a, int b);
void func(int a, int b);

int main()
{
   func = (func_type)GetProcAddress(NULL, "func");
}

【问题讨论】:

  • 这里没有定义任何函数。您正在定义函数 pointer,它指向其他已定义的函数。
  • 请同时发布“您尝试更改它”的代码
  • 除了理智之外,没有什么能阻止你使用void (*func)(int,int);main,做func = (void (*)(int,int))GetProcAddress(NULL, "func");。您会很快意识到,使用原始代码显示的在类型别名中隐藏指针类型的两个真正有效原因之一是多么方便(另一个是黑盒“句柄”API)。
  • 如果使用typedef void func_type(int,int);,可能会更容易掌握。然后您可以将func 定义为func_type *func。因为func 是一个指向函数的指针。演员表将是 ` ... = (func*)GetProcAddress(...)`。
  • 您的请求是不可能的 - GetProcAddress 返回一个指针,这是存储函数地址的唯一方法。如果您希望函数名称在编译时绑定到某个称为早期绑定且不是通过运行时调用完成的库函数GetProcAddress

标签: c function-pointers


【解决方案1】:

C 中的函数的行为类似于数组。它们都衰减为指针。每当使用函数名时,它都会自动衰减为指向该函数的指针。例外是 &sizeof 运算符。运算符sizeof 不接受函数作为操作数。这就是为什么foo&foo 是等价的。

函数本身不能被设计修改。任何修改它的尝试,即通过memcpy-ing 到函数指针都是未定义的行为

令人惊讶的是,函数调用运算符()将函数作为操作数,而是将指向函数的指针

因此,函数调用

foo(1);

其实是

(&foo)(1);

因为foo 在评估函数调用之前衰减到&foo

这就是为什么在函数调用操作数中可以互换使用函数和函数指针的原因。

void foo(int) { ... }
void (*bar)(int);

foo(1); // foo decays to &foo which is a function pointer
bar(2); // bar is already a function pointer

为了解决最初的问题,我建议保留func 是一个函数指针,它最初指向某个专用函数,但以后可以覆盖它:

typedef void func_type(int,int);

void default_func(int a, int b) { ... }

funt_type* func = default_func; // decays to &default_func !

int main()
{
   func(1,2); // calls default_func
   func = (func_type*)GetProcAddress(NULL, "func");
   func(3,4); // calls func from dll/so
}

我决定使用函数类型(不是函数指针类型),这有点不正统。 IMO,它使语法在视觉上更令人愉悦,并且更容易被人类解析。此外,它明确了什么是指针什么不是。

【讨论】:

  • 函数不是对象。 C 中的对象是“执行环境中的数据存储区域,其内容可以表示值”(C 2018 3.15 1)。 C 对对象和函数有不同的规则,包括将对象指针转换为指向不同对象类型的指针(6.3.2.3 7)以及将函数指针转换为指向不同函数类型的指针(6.3.2.3 8)的不同规则。
  • 您可能想要澄清或删除“例外是&”。我想我知道你想说什么,但不确定。
  • 将函数指示符自动转换为指针有两个例外,当它是sizeof 的操作数和当它是一元& 的操作数时。虽然sizeof 没有为函数定义,但except 很重要,否则sizeof func 将转换为sizeof &func,然后sizeof 将给出指向函数的指针的大小。
  • 函数不是左值(C 2018 6.3.2.1 1:“lvalue 是一个表达式(对象类型不是void),它可能指定一个对象...... ”
  • @EricPostpischil,已修复,感谢您指出函数不是对象。坦率地说,我一直认为函数只是一种“特殊”类型的对象。如果不是对象,那么也不是左值。
【解决方案2】:

typedef void (*func_type)(int a, int b);func_type 声明为一个指向函数的类型。然后func_type func; 声明func 是一个指针。您提出的替代方案 void func(int a, int b);func 声明为一个函数。

由于您可以分配给指针,func = …; 适用于第一个声明。由于您无法分配给函数,func = …; 不适用于第二个声明。

要在不使用typedef 的情况下将func 声明为指向函数的指针,请使用void (*func)(int, int);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-22
    • 1970-01-01
    • 2014-05-03
    • 1970-01-01
    • 2018-01-28
    • 1970-01-01
    • 2011-09-17
    • 1970-01-01
    相关资源
    最近更新 更多