[{"data":1,"prerenderedAt":530},["ShallowReactive",2],{"page-\u002Fcpp\u002Fc实现闭包":3},{"id":4,"title":5,"body":6,"description":12,"extension":524,"meta":525,"navigation":370,"path":526,"seo":527,"stem":528,"__hash__":529},"content\u002Fcpp\u002FC实现闭包.md","C实现闭包",{"type":7,"value":8,"toc":522},"minimark",[9,13,16,19,109,112,192,195,284,287,294,297,478,481,484,487,495,507,518],[10,11,12],"p",{},"C语言本身是没有闭包的因为C的函数栈是后进先出，函数已返回，栈帧就会销毁，局部变量就会随之消失，要实现闭包，就要手动模拟v8那套把逃逸的变量放在堆上。",[10,14,15],{},"闭包可以通过函数指针 + 捕获的环境。",[10,17,18],{},"首先先实现一个闭包的结构体，首先需要函数指针和环境数据，然后是创建闭包和销毁闭包。",[20,21,26],"pre",{"className":22,"code":23,"language":24,"meta":25,"style":25},"language-c shiki shiki-themes github-light github-dark","\u002F\u002F闭包结构体\ntypedef struct { \n    void* (*fn)(void *env, void *args);\n    void* env;\n} Closure;\n\u002F\u002F环境结构体\ntypedef struct CounterEnv\n{\n    \u002F* data *\u002F\n    int count;\n    int step;\n} CounterEnv;\ntypedef void* (*ClosureFn)(void* env, void* args); \u002F\u002F closurefn type\n\n","c","",[27,28,29,37,43,49,55,61,67,73,79,85,91,97,103],"code",{"__ignoreMap":25},[30,31,34],"span",{"class":32,"line":33},"line",1,[30,35,36],{},"\u002F\u002F闭包结构体\n",[30,38,40],{"class":32,"line":39},2,[30,41,42],{},"typedef struct { \n",[30,44,46],{"class":32,"line":45},3,[30,47,48],{},"    void* (*fn)(void *env, void *args);\n",[30,50,52],{"class":32,"line":51},4,[30,53,54],{},"    void* env;\n",[30,56,58],{"class":32,"line":57},5,[30,59,60],{},"} Closure;\n",[30,62,64],{"class":32,"line":63},6,[30,65,66],{},"\u002F\u002F环境结构体\n",[30,68,70],{"class":32,"line":69},7,[30,71,72],{},"typedef struct CounterEnv\n",[30,74,76],{"class":32,"line":75},8,[30,77,78],{},"{\n",[30,80,82],{"class":32,"line":81},9,[30,83,84],{},"    \u002F* data *\u002F\n",[30,86,88],{"class":32,"line":87},10,[30,89,90],{},"    int count;\n",[30,92,94],{"class":32,"line":93},11,[30,95,96],{},"    int step;\n",[30,98,100],{"class":32,"line":99},12,[30,101,102],{},"} CounterEnv;\n",[30,104,106],{"class":32,"line":105},13,[30,107,108],{},"typedef void* (*ClosureFn)(void* env, void* args); \u002F\u002F closurefn type\n",[10,110,111],{},"创建和销毁的方法：",[20,113,115],{"className":22,"code":114,"language":24,"meta":25,"style":25},"Closure* closure_new(ClosureFn fn, void* env) {\n    Closure* c = malloc(sizeof(Closure));\n    if (!c) return NULL;\n    c -> fn = fn;\n    c -> env = env;\n    return c;\n}\nvoid closure_free(Closure* c, void (*free_env)(void*)) {\n    if (!c) return;\n    if (free_env && c-> env) free_env(c->env);\n    free(c);\n}\nvoid* closure_call(Closure* closure, void* args) {\n    return closure->fn(closure->env, args);\n}\n",[27,116,117,122,127,132,137,142,147,152,157,162,167,172,176,181,187],{"__ignoreMap":25},[30,118,119],{"class":32,"line":33},[30,120,121],{},"Closure* closure_new(ClosureFn fn, void* env) {\n",[30,123,124],{"class":32,"line":39},[30,125,126],{},"    Closure* c = malloc(sizeof(Closure));\n",[30,128,129],{"class":32,"line":45},[30,130,131],{},"    if (!c) return NULL;\n",[30,133,134],{"class":32,"line":51},[30,135,136],{},"    c -> fn = fn;\n",[30,138,139],{"class":32,"line":57},[30,140,141],{},"    c -> env = env;\n",[30,143,144],{"class":32,"line":63},[30,145,146],{},"    return c;\n",[30,148,149],{"class":32,"line":69},[30,150,151],{},"}\n",[30,153,154],{"class":32,"line":75},[30,155,156],{},"void closure_free(Closure* c, void (*free_env)(void*)) {\n",[30,158,159],{"class":32,"line":81},[30,160,161],{},"    if (!c) return;\n",[30,163,164],{"class":32,"line":87},[30,165,166],{},"    if (free_env && c-> env) free_env(c->env);\n",[30,168,169],{"class":32,"line":93},[30,170,171],{},"    free(c);\n",[30,173,174],{"class":32,"line":99},[30,175,151],{},[30,177,178],{"class":32,"line":105},[30,179,180],{},"void* closure_call(Closure* closure, void* args) {\n",[30,182,184],{"class":32,"line":183},14,[30,185,186],{},"    return closure->fn(closure->env, args);\n",[30,188,190],{"class":32,"line":189},15,[30,191,151],{},[10,193,194],{},"然后是计数器部分，计数器可以创建、执行、销毁：",[20,196,198],{"className":22,"code":197,"language":24,"meta":25,"style":25},"void* counter_fn(void* env, void* args) {\n    CounterEnv* e = (CounterEnv*) env;\n    if (args) e->step=*(int*)args;\n    e->count += e->step;\n    int* result = malloc(sizeof(int));\n    *result=e->count;\n    return result;\n}\nvoid counter_env_free(void* env) {\n    free(env);\n}\nClosure* make_counter(int initial, int step) {\n    CounterEnv* env = malloc(sizeof(CounterEnv));\n    env->count=initial;\n    env->step=step;\n    return closure_new(counter_fn, env);\n}\n",[27,199,200,205,210,215,220,225,230,235,239,244,249,253,258,263,268,273,279],{"__ignoreMap":25},[30,201,202],{"class":32,"line":33},[30,203,204],{},"void* counter_fn(void* env, void* args) {\n",[30,206,207],{"class":32,"line":39},[30,208,209],{},"    CounterEnv* e = (CounterEnv*) env;\n",[30,211,212],{"class":32,"line":45},[30,213,214],{},"    if (args) e->step=*(int*)args;\n",[30,216,217],{"class":32,"line":51},[30,218,219],{},"    e->count += e->step;\n",[30,221,222],{"class":32,"line":57},[30,223,224],{},"    int* result = malloc(sizeof(int));\n",[30,226,227],{"class":32,"line":63},[30,228,229],{},"    *result=e->count;\n",[30,231,232],{"class":32,"line":69},[30,233,234],{},"    return result;\n",[30,236,237],{"class":32,"line":75},[30,238,151],{},[30,240,241],{"class":32,"line":81},[30,242,243],{},"void counter_env_free(void* env) {\n",[30,245,246],{"class":32,"line":87},[30,247,248],{},"    free(env);\n",[30,250,251],{"class":32,"line":93},[30,252,151],{},[30,254,255],{"class":32,"line":99},[30,256,257],{},"Closure* make_counter(int initial, int step) {\n",[30,259,260],{"class":32,"line":105},[30,261,262],{},"    CounterEnv* env = malloc(sizeof(CounterEnv));\n",[30,264,265],{"class":32,"line":183},[30,266,267],{},"    env->count=initial;\n",[30,269,270],{"class":32,"line":189},[30,271,272],{},"    env->step=step;\n",[30,274,276],{"class":32,"line":275},16,[30,277,278],{},"    return closure_new(counter_fn, env);\n",[30,280,282],{"class":32,"line":281},17,[30,283,151],{},[10,285,286],{},"计数器是一个简单例子，用于验证闭包机制是否是正常工作的。因为count和step都是从make_counter捕获的，count在函数返回之后任然存货，多次调用间保持。每次调用count都累加，证明环境是共享的，c1和c2有独立env，互不干扰。",[10,288,289,290,293],{},"这里的Closure结构体就类似于v8里的函数对象，然后closure.env就是我们之前提到的 ",[27,291,292],{},"[[Environment]]"," 槽，env指向的堆数据就是Context上下文。",[10,295,296],{},"使用：",[20,298,300],{"className":22,"code":299,"language":24,"meta":25,"style":25},"int main() {\n    Closure* c1 = make_counter(0, 1); \u002F\u002F 0开始，每次+1\n    Closure* c2 = make_counter(100, 10);\n    for (int i = 0; i \u003C 3; i++) {\n        int* r = (int*)closure_call(c1, NULL);\n        printf(\"c1: %d\\n\", *r);\n        free(r);\n    }\n    for (int i = 0; i \u003C 2; i++) {\n    int* r = (int*)closure_call(c2, NULL);\n    printf(\"c2: %d\\n\", *r);\n    free(r);\n    }\n\n    int new_step = 5;\n    int *r = (int *)closure_call(c1, &new_step);\n    printf(\"c1 (step=5): %d\\n\", *r);\n    free(r);\n\n    closure_free(c1, counter_env_free);\n    closure_free(c2, counter_env_free);\n\n    return 0;\n}\n\n[18:17:17] PS E:\\leetcode\\CPP\\build>  .\\closure.exe\nc1: 1\nc1: 2\nc1: 3\nc2: 110\nc2: 120\nc1 (step=5): 8\n[18:17:19] PS E:\\leetcode\\CPP\\build>\n",[27,301,302,307,312,317,322,327,332,337,342,347,352,357,362,366,372,377,382,387,392,397,403,409,414,420,425,430,436,442,448,454,460,466,472],{"__ignoreMap":25},[30,303,304],{"class":32,"line":33},[30,305,306],{},"int main() {\n",[30,308,309],{"class":32,"line":39},[30,310,311],{},"    Closure* c1 = make_counter(0, 1); \u002F\u002F 0开始，每次+1\n",[30,313,314],{"class":32,"line":45},[30,315,316],{},"    Closure* c2 = make_counter(100, 10);\n",[30,318,319],{"class":32,"line":51},[30,320,321],{},"    for (int i = 0; i \u003C 3; i++) {\n",[30,323,324],{"class":32,"line":57},[30,325,326],{},"        int* r = (int*)closure_call(c1, NULL);\n",[30,328,329],{"class":32,"line":63},[30,330,331],{},"        printf(\"c1: %d\\n\", *r);\n",[30,333,334],{"class":32,"line":69},[30,335,336],{},"        free(r);\n",[30,338,339],{"class":32,"line":75},[30,340,341],{},"    }\n",[30,343,344],{"class":32,"line":81},[30,345,346],{},"    for (int i = 0; i \u003C 2; i++) {\n",[30,348,349],{"class":32,"line":87},[30,350,351],{},"    int* r = (int*)closure_call(c2, NULL);\n",[30,353,354],{"class":32,"line":93},[30,355,356],{},"    printf(\"c2: %d\\n\", *r);\n",[30,358,359],{"class":32,"line":99},[30,360,361],{},"    free(r);\n",[30,363,364],{"class":32,"line":105},[30,365,341],{},[30,367,368],{"class":32,"line":183},[30,369,371],{"emptyLinePlaceholder":370},true,"\n",[30,373,374],{"class":32,"line":189},[30,375,376],{},"    int new_step = 5;\n",[30,378,379],{"class":32,"line":275},[30,380,381],{},"    int *r = (int *)closure_call(c1, &new_step);\n",[30,383,384],{"class":32,"line":281},[30,385,386],{},"    printf(\"c1 (step=5): %d\\n\", *r);\n",[30,388,390],{"class":32,"line":389},18,[30,391,361],{},[30,393,395],{"class":32,"line":394},19,[30,396,371],{"emptyLinePlaceholder":370},[30,398,400],{"class":32,"line":399},20,[30,401,402],{},"    closure_free(c1, counter_env_free);\n",[30,404,406],{"class":32,"line":405},21,[30,407,408],{},"    closure_free(c2, counter_env_free);\n",[30,410,412],{"class":32,"line":411},22,[30,413,371],{"emptyLinePlaceholder":370},[30,415,417],{"class":32,"line":416},23,[30,418,419],{},"    return 0;\n",[30,421,423],{"class":32,"line":422},24,[30,424,151],{},[30,426,428],{"class":32,"line":427},25,[30,429,371],{"emptyLinePlaceholder":370},[30,431,433],{"class":32,"line":432},26,[30,434,435],{},"[18:17:17] PS E:\\leetcode\\CPP\\build>  .\\closure.exe\n",[30,437,439],{"class":32,"line":438},27,[30,440,441],{},"c1: 1\n",[30,443,445],{"class":32,"line":444},28,[30,446,447],{},"c1: 2\n",[30,449,451],{"class":32,"line":450},29,[30,452,453],{},"c1: 3\n",[30,455,457],{"class":32,"line":456},30,[30,458,459],{},"c2: 110\n",[30,461,463],{"class":32,"line":462},31,[30,464,465],{},"c2: 120\n",[30,467,469],{"class":32,"line":468},32,[30,470,471],{},"c1 (step=5): 8\n",[30,473,475],{"class":32,"line":474},33,[30,476,477],{},"[18:17:19] PS E:\\leetcode\\CPP\\build>\n",[10,479,480],{},"C函数栈",[10,482,483],{},"这是程序运行时用于管理函数调用的一种后进先出LIFO的内存结构，由操作系统和CPU共同维护，负责保存函数调用时候返回的地址、参数、局部变量等信息。",[10,485,486],{},"每当一个函数被调用，系统就会在栈上分配一块内存，称为栈帧。函数执行完毕后，这块内存被自动回收。",[20,488,493],{"className":489,"code":491,"language":492},[490],"language-text","高地址\n  ┌─────────────┐\n  │   ...       │\n  ├─────────────┤\n  │  main 栈帧  │\n  ├─────────────┤\n  │  foo 栈帧   │  ← 当前执行 foo\n  ├─────────────┤\n  │  bar 栈帧   │  ← bar 被 foo 调用\n  ├─────────────┤\n  │   ...       │\n  └─────────────┘\n低地址\n","text",[27,494,491],{"__ignoreMap":25},[10,496,497,498,502,503,506],{},"一个典型的栈帧包含了返回地址，当函数执行完了之后就会回到调用者的哪条指令；参数，传递给函数的实参，部分通过寄存器传递；局部变量，",[499,500,501],"strong",{},"函数内部定义的变量","；保存的寄存器，",[499,504,505],{},"调用寄存器的值","，用于恢复现场；栈帧指针RBP，指向栈帧底部；栈指针RSP指向当前栈帧顶部。",[10,508,509,510,513,514,517],{},"C的线程栈通常1MB(windows)，或者8MB(linux)，栈溢出就会触发",[27,511,512],{},"EXCEPTION_STACK_OVERFLOW"," 或 ",[27,515,516],{},"SIGSEGV","。",[519,520,521],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":25,"searchDepth":39,"depth":39,"links":523},[],"md",{},"\u002Fcpp\u002Fc实现闭包",{"description":12},"cpp\u002FC实现闭包","MN9fG3YXRTKLQT973nIwarrmCpIaOgAzFbL6ly95P_g",1791042461650]