You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言中传递函数与函数指针的差异及规范用法问询

嘿,我来帮你把这些函数指针的疑惑理清楚——这确实是C语言里一个容易让人懵的点,尤其是因为标准里有一些「隐式转换」的规则在背后悄悄起作用。咱们一个个来拆解你的问题:

你的疑问解答

1. 这4个片段是否存在实际差异?为何表现完全相同?

这四种写法在标准C里没有任何实际运行时差异。核心原因是C语言对函数名和函数参数的两套自动转换规则:

  • 当函数名(比如print)出现在表达式中(除了作为sizeof、&运算符的操作数,或是字符串化宏的参数时),会自动被转换为指向该函数的指针;
  • 在函数参数声明里,void(f)()这种「函数类型」的写法,会被编译器自动调整为void(*f)()——也就是函数指针类型,类似数组参数会退化成指针的规则。

所以不管你传print还是&print,不管参数声明成函数还是函数指针,最终传递的都是同一个函数指针,运行时表现自然完全一致。

2. 若无运行时差异,编译器做了哪些处理?哪种是标准写法?

编译器主要做了两类隐式类型转换:

  1. 传参阶段:把函数名print自动转换成&print(函数指针);
  2. 参数声明阶段:把void(f)()这种函数类型的参数,调整为void(*f)()函数指针类型——这是C标准明确规定的语法规则。

两种写法都是标准允许的,但**void(*f)()是更清晰的标准写法**,它直接明确了参数是函数指针;而void(f)()属于语法糖,本质和前者等价。传参时print和&print也都符合标准,效果无差。

3. 应选择哪种写法?

推荐你使用**传参用print,参数声明用void(*f)()**的组合:

  • void(*f)()的声明方式能让其他开发者一眼看懂这是个函数指针参数,避免歧义;
  • 传参用print是C社区最常用的写法,简洁且符合大众编码习惯。

如果团队有统一的编码规范,优先遵循规范即可。

4. 调用传入的函数时用f()还是(*f)()?

两种写法完全等价,随便用哪个都可以。因为当你对函数指针用*解引用时,得到的函数类型会立刻被转换回函数指针(除非在sizeof或&操作里)——甚至你写(**f)()、(***f)()也能正常运行,但完全没必要多此一举。f()是最简洁直观的写法,优先用这个。

5. 为何sizeof(print)结果为1?此时获取的是什么大小?

这其实是编译器的非标准扩展行为。因为C标准明确规定:sizeof不能作用于函数类型。你的Apple LLVM编译器允许了这个操作,但返回的1只是一个占位值——函数是代码段里的指令序列,根本没有「大小」这个概念。

如果你加上-pedantic编译选项,编译器会给出警告,提示你sizeof不能用于函数类型,这才是符合标准的反馈。

6. 为何片段1、3中,参数声明为void(f)()时sizeof(f)仍为8?

因为前面提到的参数类型调整规则:在函数参数声明里,void(f)()会被编译器自动转换成void(*f)()——也就是说,f本质上是一个函数指针变量,而不是函数类型。在64位的macOS系统里,指针的大小是8字节,所以sizeof(f)返回8是完全符合标准的结果。


内容的提问来源于stack exchange,提问作者Rafael Eyng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 12:47:30