在 C 语言中定义函数指针?

Defining function pointer in C?

提问人:mrn 提问时间:9/4/2023 最后编辑:Vlad from Moscowmrn 更新时间:9/4/2023 访问量:100

问:

  1. 最近,我发现了一种用 C 语言定义函数指针的令人惊讶的方法:
typedef void (func_type)(void);
func_type *func_ptr;

这是定义函数指针的正确方法吗?

  1. 如果我们func_obj定义如下,这个对象的类型是什么,这个对象可以用来做什么?
#include <stdio.h>

typedef void (func_type)(void);
func_type *func_ptr;

func_type func_obj;

int main()
{
  printf("Size of func_obj: %zu\n", sizeof func_obj);
  printf("Size of func_ptr: %zu\n", sizeof func_ptr);
  return 0;
}

代码打印:

Size of func_obj: 1
Size of func_ptr: 8
C typedef 函数声明

评论

0赞 pmacfarlane 9/4/2023
这是否回答了您的(一些)问题?'sizeof (函数名称)' 返回什么?
1赞 Ian Abbott 9/4/2023
是的,对象类型(包括函数指针类型)和函数类型都可以作为标准类型定义。将运算符应用于函数类型是违反约束的。sizeof
1赞 Ian Abbott 9/4/2023
如果要使用相同的原型(例如查找表)转发声明一大堆函数,则类型定义函数类型对于节省类型(并易于维护)非常有用。
0赞 tstanisl 9/4/2023
自 C 诞生以来,它就完全有效。在 C23 中,甚至可以做到.typeof(void(void))* func_ptr;
0赞 John Bollinger 9/4/2023
由于 C 在函数和对象之间严格区分,因此此示例中的标识符具有误导性。它标识一个函数,而不是一个对象,尽管它的(函数)类型是通过 ed 类型名称传达的。func_objtypedef

答:

2赞 KamilCuk 9/4/2023 #1

这是定义函数指针的正确方法吗?

是的。

我更喜欢定义一个函数类型,然后使用它。立即可见的是指针,vs 隐藏了该信息。*func_type *typedef void (*func_type)(void); func_type func;

func_obj如下,如果这个对象是什么类型?

func_obj从字面上看是一个函数。考虑:

#include <stdio.h>
typedef void func_type(void);
// forward declaration of a function
void func_obj(void);
// typedef is just an alias, exactly the same as above
func_type func_obj;
// for function definition, we have to use a ()
void func_obj(void) {
    printf("Inside func_obj\n");
}
int main() {
     func_obj();
}

从技术上讲,做是无效的 - 'sizeof (函数名称)' 返回什么?.sizeof(func_obj)

这个对象可以用来做什么?

好吧,就像一个函数,用于调用它。Alias 可用于使函数类型保持同步。

2赞 Vlad from Moscow 9/4/2023 #2

这些声明

typedef void (func_type)(void);
func_type *func_ptr;

类似于声明,例如

typedef int T;
T *int_ptr; 

因此,为函数类型引入别名的 typedef 没有任何问题。

请注意,这个 typedef 声明

typedef void (func_type)(void);

相当于

typedef void func_type(void);

本声明

func_type func_obj;

声明一个名称为 的函数。func_objvoid( void )

例如,这样的声明允许在一行中列出函数,而不重复其参数列表。

本声明

printf("Size of func_obj: %zu\n", sizeof func_obj);

根据 C 标准,它是无效的,因为您不能将运算符应用于函数。sizeof

来自 C 标准(6.5.3.4 大小和对齐运算符)

1 sizeof 运算符不应应用于具有 函数类型或不完整类型,到括号内的名称中。 类型,或指定位字段成员的表达式。这 alignof 运算符不得应用于函数类型或 不完整类型。

但是,某些编译器可以有自己的扩展,这与 C 标准相矛盾。

评论

0赞 Elzaidir 9/4/2023
有趣的是,GCC 返回的大小为 1。这没有多大意义,它应该抛出一个错误。我想知道理由是什么。
0赞 KamilCuk 9/4/2023
@Elzaidir gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html
0赞 Elzaidir 9/4/2023
@KamilCuk 谢谢你,很有意思。函数和 void 类型的指针算术需要这是有道理的。
0赞 Lundin 9/4/2023
@KamilCuk 这不是一个理由。那就是“开发人员 x 很无聊,发明了一个新的 GNU C 功能,只是为了它”。我仍然看不出你为什么要在空指针或函数指针上做指针算术 - 这样做的需要源于混乱的程序设计。
2赞 Lundin 9/4/2023 #3

这是定义函数指针的正确方法吗?

是的。有两种不同的编码风格:

  • 要么是一个函数,并将一个对象声明为指向该函数的指针:;typedef

    typedef void func_t (void);
    ...
    func_t* fptr;
    
  • 或者将指针隐藏在 :typedef

    typedef void (*func_t) (void);
    ...
    func_t fptr;
    

使用哪一个主要是偏好问题。

前者使函数指针的行为与对象指针一样,因此它有利于一致性和我个人推荐的内容。将指针隐藏在 .好的代码应该是自记录的。typedef

后者在历史上是最常见的,您也应该了解它。在我转换为以前的风格之前,我也使用了很长时间。


如果我们func_obj定义如下,这个对象的类型是什么,这个对象可以用来做什么?

它声明一个函数类型。这是另一个危险的 GNU C 问题 - 你不能在符合 C 的函数上应用(参见约束 6.5.3.4)。gcc 和 clang 在这里显然是不合格的,除非你添加 .sizeof-pedantic

至于这个“功能”的目的是什么......与任何其他此类稍微有用的 GNU C 特性一样:为了实现新特性而实现。我在任何地方都找不到任何理由或解释来解释这个“功能”实际上有什么好处。它的处是显而易见的:它降低了操作员的类型安全性。sizeof

评论

0赞 Elzaidir 9/4/2023
如@KamilCuk所述,这里解释了函数为 1 背后的理性。简而言之,这是允许对函数指针进行算术运算的副作用。现在,为什么允许对函数指针进行算术运算是另一个话题。sizeof
1赞 Lundin 9/4/2023
@Elzaidir 这不是一个理由,这就像说“我们用厨房水槽代替了汽车的轮子,以便可以使用厨房水槽驾驶汽车”。