C语言递归schema函数调用plus函数的运行原理解析
问题背景
我尝试使用在线调试器分析一段C语言代码的运行逻辑,但始终无法理清其执行流程。
使用的在线C编译器为OnlineGDB提供的在线C编译环境。
待分析代码
#include <stdio.h> unsigned int plus(unsigned int x, unsigned int y){ return x+y; } unsigned int schema (unsigned int x, unsigned int y, unsigned int a, unsigned int (*f)(unsigned int, unsigned int)){ return((y==0)?a:(*f)(schema(x,y-1,a,f),x)); } unsigned int prod(unsigned int x, unsigned int y){ return(schema(x,y,0,plus)); } int main() { int m,n; printf("Donner deux nombres ? : "); scanf("%d %d", &m, &n); printf("%d * %d = %d\n", m, n, prod(m,n)); return 0; }
核心疑问
schema 函数是如何传入正确参数调用 plus 函数,最终实现乘法计算的?
对应代码可在OnlineGDB平台在线运行调试。
调试记录
输入3和2时的GDB调试过程记录如下:
Reading symbols from a.out... (gdb) run Starting program: /home/a.out Donner deux nombres ? : 3 2 Breakpoint 2, prod (x=21845, y=1431655088) at main.c:20 20 unsigned int prod(unsigned int x, unsigned int y){ (gdb) step Breakpoint 1, prod (x=3, y=2) at main.c:21 21 return(schema(x,y,0,plus)); (gdb) step Breakpoint 4, schema (x=32767, y=4294962119, a=0, f=0xf0b5ff) at main.c:16 16 unsigned int schema (unsigned int x, unsigned int y, unsigned int a, unsigned int (*f)(unsigned int, unsigned int)){ (gdb) step Breakpoint 3, schema (x=3, y=2, a=0, f=0x555555555189 <plus>) at main.c:17 17 return((y==0)?a:(*f)(schema(x,y-1,a,f),x)); (gdb) step Breakpoint 4, schema (x=0, y=0, a=0, f=0x0) at main.c:16 16 unsigned int schema (unsigned int x, unsigned int y, unsigned int a, unsigned int (*f)(unsigned int, unsigned int)){ (gdb) step Breakpoint 3, schema (x=3, y=1, a=0, f=0x555555555189 <plus>) at main.c:17 17 return((y==0)?a:(*f)(schema(x,y-1,a,f),x)); (gdb) step Breakpoint 4, schema (x=0, y=24, a=0, f=0x0) at main.c:16 16 unsigned int schema (unsigned int x, unsigned int y, unsigned int a, unsigned int (*f)(unsigned int, unsigned int)){ (gdb) step Breakpoint 3, schema (x=3, y=0, a=0, f=0x555555555189 <plus>) at main.c:17 17 return((y==0)?a:(*f)(schema(x,y-1,a,f),x)); (gdb) step 18 } (gdb) step Breakpoint 6, plus (x=3, y=0) at main.c:12 12 unsigned int plus(unsigned int x, unsigned int y){ (gdb) step Breakpoint 5, plus (x=0, y=3) at main.c:13 13 return x+y; (gdb) step 14 } (gdb) step schema (x=3, y=1, a=0, f=0x555555555189 <plus>) at main.c:18 18 } (gdb) step Breakpoint 6, plus (x=3, y=1) at main.c:12 12 unsigned int plus(unsigned int x, unsigned int y){ (gdb) step Breakpoint 5, plus (x=3, y=3) at main.c:13 13 return x+y; (gdb) step 14 } (gdb) step schema (x=3, y=2, a=0, f=0x555555555189 <plus>) at main.c:18 18 } (gdb) step prod (x=3, y=2) at main.c:22 22 } (gdb) step __printf (format=0x555555556023 "%d * %d = %d\n") at printf.c:28 28 printf.c: No such file or directory. (gdb) continue Continuing. 3 * 2 = 6 [Inferior 1 (process 2233) exited normally] (gdb)
运行逻辑说明
这段代码靠递归累加实现乘法,各部分作用和执行流程如下:
schema是通用递归工具函数,第四个参数是函数指针,用来指定每一步递归要执行的运算,第三个参数a是累计计算的初始值,乘法场景下初始传0。- 递归终止条件是计数参数
y减到0,此时直接返回存好的累计结果a。 - 未触发终止条件时,会先递归调用自身将y减1,拿到上一层的计算结果,再把这个结果和固定值x传给传入的运算函数
f,计算得到的值就是当前层的返回值。 prod函数调用schema时,传入的运算函数是plus(即加法运算),逻辑等价于把x重复累加y次,最终结果自然就是x与y的乘积。
以输入3和2为例,完整调用顺序和调试记录完全对应:
- 最外层调用
schema(3,2,0,plus),此时y=2不等于0,需要先计算schema(3,1,0,plus)的返回值,再将返回值和3传入plus做加法 - 进入
schema(3,1,0,plus),y=1也不等于0,需要先计算schema(3,0,0,plus)的返回值,再将结果和3传入plus - 进入
schema(3,0,0,plus),y=0触发终止条件,直接返回初始值0 - 回到第二层
schema调用,执行plus(0,3)得到3,作为schema(3,1,0,plus)的返回值 - 回到最外层
schema调用,执行plus(3,3)得到6,也就是3*2的最终计算结果
调试过程中看到的参数异常栈帧(比如x=32767、f为空指针这类),是GDB还未单步进入对应函数、栈帧未初始化完成时读到的内存脏值,无需在意,单步进入函数后参数值就会恢复正常。
内容的提问来源于stack exchange,提问作者Maykiwo GNO
相关产品推荐
相关产品推荐

