首页 / 财经 / 理财 / 正文

指针函数(你所不知道的C语言:指针篇(函数指针))

放大字体  缩小字体 来源:太原写字楼出租 2026-04-17 17:30  浏览次数:5

Function Pointer

int main() { return (********puts)("Hello"); }

为何可以运行?

  • C99 [ 6.3.2.1 ] A function designator is an expression that has function type

=>> * is Right associative operator

  • C99 [6.5.1 ] It is an lvalue, a function designator, or avoid expression if the unparenthesized expression is, respectively, an lvalue, a function designator, or avoid expression.
  • C99 [6.5.3.2-4] The unary * operator denotes indirection. If the operand points to a function, the result is a function designator

补充说明:C语言标准规定,函数指示符(function designator,即函数名字)既不是左值,也不是右值。

除了作为sizeof或取地址&的操作数,函数指示符在表达式中自动转换为函数指针类型右值。因此通过一个函数指针调用所指的函数,不需要在函数指针前加取值或反引用(*)运算符

  • 程序示例
#include <stdio.h>// fptr is a pointer, point to a functionvoid (*fptr) ();// an empty functionvoid test() {	;}int main() {	fptr = test;	printf("test: %x, fptr: %x\n", test, fptr);	return 0;}
  • 根据 6.3.2.1
void (*fptr)();void test();fptr = test;

test: void (), 会被转成 function pointer: void (*) ()

fptr is a pointer to function with returning type,

  • 根据 6.5.3.2

(*fptr) is a function designator, a function designator will be converted to pointer.

type of (*fptr): void ()

我们可以利用 gdb 去查看这些数值,搭配 print 指令

(gdb) print test$1 = {void ()} 0x400526 <test>(gdb) print test$2 = {void ()} 0x400526 <test>(gdb) print fptr$3 = (void (*)()) 0x400526 <test>(gdb) print (*fptr)$4 = {void ()} 0x400526 <test>(gdb) print (**fptr)$5 = {void ()} 0x400526 <test>

test 是一个 function designator ,因为不是搭配 &, sizeof 使用,所以会被转成为 pointer to function

(*fptr) 是一個 function pointer 搭配 * (dereference, indirection) operator 使用,则它的结果会被转成为一个 function designator

所以 (**fptr) 要拆成两个部分: (* ( *fptr) ), 里面的 *fptr 是个 function designator, 但是还是会被转成一个 pointer to function,我们可注记为 fptr

又,外面又有一个 * operator, ( *fptr’ 是個 function designator, 最后还是会被转化为 pointer to function

但是,0x400526 这个数值是怎么来的呢?

我们可以使用以下指令观察:

$ gdb -o fp -g fp.c ` & ` objdump -d fp `

参考输出里面的一段:

0000000000400526 <test>:400526: 55 push %rbp400527: 48 89 e5 mov %rsp,%rbp40052a: 90 nop40052b: 5d pop %rbp40052c: c3 retq

这个数值其实是可执行文件反编译后的函数入口,但是这个数值并非是在实际内存中的数值,而是虚拟存储器的地址。

由于puts 的 function prototype 是 int puts(const char *s),因此每次经过 * operator 运算后得到的结果是仍然是 int。所以,* 的数目不會影响结果。最后return 的值是根据 s 的长度加上 ’\n’。而这个例子 return 给 main 的值是 6。

Address and indirection operators

对应到 C99/C11 规范 [ 6.5.3.2 ],& 所能操作的 operand 只能是:

  • function designator - 基本上就是 function name
  • [] or * 的操作结果:跟这两个作用时,基本上就是相消

[] - & 会消失,而 [] 会被转换成只剩 + (注:原本 [] 会是 + 搭配 *)

bit-field:一种在 struct 或 union 中使用用来节省内存空间的object;
特別的用途:沒有名称的 bit-field 可以
做为padding

除了遇到 [] 或 * 外,使用 & 的结果基本上都是得到 pointer to the object 或是 function 的 address

考虑以下程序:

char str[123];

为何 str == &str 呢?

  • 实际上左右两边的类型是不一样的,只是值相同。
  • 左边的是 pointer to char:char *

Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. (C99 6.3.2.1)

  • 右边的则是 pointer to an array: char (*)[123]

除了用值相同來解释外,规范在提到 equality operators 时,也有说到类似情景

char * const pContent;

  • 指针所指向的內容不可变更 (Pointer to constant): const 在 * 之前

const char * const pContent;

Linus Torvalds 亲自教你 C 語言

  • array argument 的正确使用时机

Are there any cases of multi-dimensional arrays? Because those actually have semantic meaning outside of sizeof(), just in things like adding offsets. Eg something like

int fn(int a[][10])
  • ends up being equivalent to something like
int fn(int (*a)[10])

and "a+1" is actually 40 bytes ahead of "a", so it does not act like an "int *". (And I might have screwed that up mightily - C multidimensional arrays and the conversions to pointers are really easy to get confused about. Which is why I hope we don’t have them)

  • 艺术与核心
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))`char *`

打赏
0相关评论
热门搜索排行
精彩图片
友情链接
声明:本站信息均由用户注册后自行发布,本站不承担任何法律责任。如有侵权请告知立立即做删除处理。
违法不良信息举报邮箱:115904045
头条快讯网 版权所有
中国互联网举报中心