typedef如何为函数指针工作



我想我可能患有可怕的"意外程序员"疾病,至少在类型定义和函数指针方面是这样。所以我一直在尝试各种组合,根据我得到的所有输出来分析结果。

但当我不断尝试不同的组合,而不是分析结果时,我现在只是迷失在这个过程中。

我希望你们能帮我解决这个烂摊子。

第一个代码示例

typedef void (print)(void);
void do_something (void) { printf("Hello Worldn"); }
print *pr;
pr = &do_something;
pr(); // Hello World

第二个代码示例

typedef void (print)(void);
void do_something (void) { printf("Hello Worldn"); }
print *pr;
pr = do_something;
pr(); // Hello World

上面的两个代码示例是如何工作的,就好像"&"对函数名没有影响

第三个代码示例

typedef void (print)(void);
void do_something (void) { printf("Hello Worldn"); }
print pr;
pr = do_something; // compile error
pr = &do_something; // compile error
pr();

我希望上面的一项任务能在这里工作,但该死!我真的不懂函数指针(可能也不懂typedef)。

函数名的地址和普通函数名的含义相同,因此&对函数名没有影响。

类似地,当使用函数指针时,多重去引用也不是问题:

#include <stdio.h>
typedef void print(void);
static void dosomething(void) { printf("Hello Worldn"); }
int main(void)
{
    print *f1 = dosomething;
    print *f2 = &dosomething;
    f2();
    (f1)();
    (*f1)();
    (**f2)();
    (***f1)();
    (****f2)();
    (*****f1)();
}

在下干净地编译

gcc -O3 -g -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes 
    -Wold-style-definition -std=c99 xx.c -o xx

我不会说多颗星是好风格;事实并非如此。这是"奇怪的,(是的,你可以说)反常的"。一颗星就足够了(一颗星主要是给像我这样的人,他们在标准说"通过指针调用函数而不使用(*pointer_to_function)(arg1, arg2)表示法是可以的;如果你喜欢,你可以写pointer_to_function(arg1, arg2)"之前就学会了用C编程)。是的,这很奇怪。不,谢天谢地,没有其他类型(或一类类型)表现出同样的行为。

函数指针是函数的指针:-)这就是你如何让你的第三个样本工作:
#include <stdio.h>
typedef void (*print)(void);
//            ^
void do_something (void) { printf("Hello Worldn"); }
int main (void) {
    print pr;
    pr = do_something; // &do_something would also work.
    pr();
    return 0;
}

就使用funcName还是&funcName而言,这并不重要(至少在C中)。6.3.2.1 Lvalues, arrays and function designators节规定:

函数指示符是具有函数类型的表达式。除非它是sizeof运算符或一元&运算符,类型为"函数返回类型"的函数指示符将转换为类型为"指向函数返回类型的指针"的表达式。

事实证明,在C/C++中,funcname&funcname都会产生funcname的地址,并且可以分配给函数指针变量。实际上,这只是为语言设计语法的一个奇怪之处。

与C一样,C++也有指向函数的指针:例如,void (*)()是指向不带参数也不返回值的函数的指针。然而,C++也引入了对函数void (&)()的引用,并且两者之间存在隐式转换(尽管我记不清具体的规则)。

因此:

  • funcname是对函数的引用
  • &funcname是指向函数的指针

请注意,获取重载函数的地址(或引用)需要static_cast作为精确类型(以解决重载)。

最新更新