[{"data":1,"prerenderedAt":2977},["ShallowReactive",2],{"navigation":3,"\u002Fappendix\u002Fcli":909,"\u002Fappendix\u002Fcli-surround":2974},[4,36,56,96,230,270,414,457,508,583,649,685,767,864,900,904],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"附录","i-lucide-bookmark","\u002Fappendix","appendix",[10,12,16,20,24,28,32],{"title":5,"path":7,"stem":11,"icon":6},"appendix\u002Findex",{"title":13,"path":14,"stem":15,"icon":6},"命令行界面","\u002Fappendix\u002Fcli","appendix\u002Fcli",{"title":17,"path":18,"stem":19,"icon":6},"代码风格","\u002Fappendix\u002Fcoding_style","appendix\u002Fcoding_style",{"title":21,"path":22,"stem":23,"icon":6},"关键字列表","\u002Fappendix\u002Fkeyword","appendix\u002Fkeyword",{"title":25,"path":26,"stem":27,"icon":6},"运算符优先级和结合方向","\u002Fappendix\u002Foperator","appendix\u002Foperator",{"title":29,"path":30,"stem":31,"icon":6},"预处理指令","\u002Fappendix\u002Fpreprocessor","appendix\u002Fpreprocessor",{"title":33,"path":34,"stem":35,"icon":6},"值类别","\u002Fappendix\u002Fvalue_category","appendix\u002Fvalue_category",{"title":37,"icon":38,"path":39,"stem":40,"children":41},"第〇章 基本概念","i-lucide-monitor","\u002Fch00","ch00",[42,44,48,52],{"title":37,"path":39,"stem":43,"icon":38},"ch00\u002Findex",{"title":45,"path":46,"stem":47,"icon":38},"计算机","\u002Fch00\u002Fcomputer","ch00\u002Fcomputer",{"title":49,"path":50,"stem":51,"icon":38},"编程","\u002Fch00\u002Fprogramming","ch00\u002Fprogramming",{"title":53,"path":54,"stem":55,"icon":38},"编程语言","\u002Fch00\u002Fprogramming_language","ch00\u002Fprogramming_language",{"title":57,"icon":58,"path":59,"stem":60,"children":61},"第一章 感性认识 C++ 程序","i-lucide-book-open","\u002Fch01","ch01",[62,64,68,72,76,80,84,88,92],{"title":57,"path":59,"stem":63,"icon":58},"ch01\u002Findex",{"title":65,"path":66,"stem":67,"icon":58},"赋值和分支","\u002Fch01\u002Fassignment_and_if","ch01\u002Fassignment_and_if",{"title":69,"path":70,"stem":71,"icon":58},"最麻烦的门槛","\u002Fch01\u002Fenvironment","ch01\u002Fenvironment",{"title":73,"path":74,"stem":75,"icon":58},"第一个 C++ 程序","\u002Fch01\u002Ffirst_program","ch01\u002Ffirst_program",{"title":77,"path":78,"stem":79,"icon":58},"输入","\u002Fch01\u002Finput","ch01\u002Finput",{"title":81,"path":82,"stem":83,"icon":58},"综合运用","\u002Fch01\u002Fintegrated_use","ch01\u002Fintegrated_use",{"title":85,"path":86,"stem":87,"icon":58},"循环","\u002Fch01\u002Floop","ch01\u002Floop",{"title":89,"path":90,"stem":91,"icon":58},"更多的输出","\u002Fch01\u002Fmore_output","ch01\u002Fmore_output",{"title":93,"path":94,"stem":95,"icon":58},"总结","\u002Fch01\u002Fsummary","ch01\u002Fsummary",{"title":97,"path":98,"stem":99,"children":100,"icon":102},"第二章 理性认识 C++ 程序","\u002Fch02","ch02\u002Findex",[101,103,149,188,227],{"title":97,"path":98,"stem":99,"icon":102},"i-lucide-code",{"title":104,"icon":105,"path":106,"stem":107,"children":108},"第 1 部分 数据成分","i-lucide-database","\u002Fch02\u002Fpart1","ch02\u002Fpart1\u002Findex",[109,110,114,118,122,126],{"title":104,"path":106,"stem":107,"icon":105},{"title":111,"path":112,"stem":113,"icon":105},"初识数组","\u002Fch02\u002Fpart1\u002Farray_glance","ch02\u002Fpart1\u002Farray_glance",{"title":115,"path":116,"stem":117,"icon":105},"常量","\u002Fch02\u002Fpart1\u002Fconstant","ch02\u002Fpart1\u002Fconstant",{"title":119,"path":120,"stem":121,"icon":105},"声明语句","\u002Fch02\u002Fpart1\u002Fdeclaration_statement","ch02\u002Fpart1\u002Fdeclaration_statement",{"title":123,"path":124,"stem":125,"icon":105},"只读变量","\u002Fch02\u002Fpart1\u002Freadonly_variable","ch02\u002Fpart1\u002Freadonly_variable",{"title":127,"icon":128,"path":129,"stem":130,"children":131},"类型系统","i-lucide-dna","\u002Fch02\u002Fpart1\u002Ftype_system","ch02\u002Fpart1\u002Ftype_system\u002Findex",[132,133,137,141,145],{"title":127,"path":129,"stem":130,"icon":128},{"title":134,"path":135,"stem":136,"icon":128},"布尔类型","\u002Fch02\u002Fpart1\u002Ftype_system\u002Fboolean_type","ch02\u002Fpart1\u002Ftype_system\u002Fboolean_type",{"title":138,"path":139,"stem":140,"icon":128},"字符类型","\u002Fch02\u002Fpart1\u002Ftype_system\u002Fcharacter_type","ch02\u002Fpart1\u002Ftype_system\u002Fcharacter_type",{"title":142,"path":143,"stem":144,"icon":128},"浮点类型","\u002Fch02\u002Fpart1\u002Ftype_system\u002Ffloat_type","ch02\u002Fpart1\u002Ftype_system\u002Ffloat_type",{"title":146,"path":147,"stem":148,"icon":128},"整型","\u002Fch02\u002Fpart1\u002Ftype_system\u002Finteger_type","ch02\u002Fpart1\u002Ftype_system\u002Finteger_type",{"title":150,"icon":151,"path":152,"stem":153,"children":154},"第 2 部分 运算成分","i-lucide-calculator","\u002Fch02\u002Fpart2","ch02\u002Fpart2\u002Findex",[155,156,160,164,168,172,176,180,184],{"title":150,"path":152,"stem":153,"icon":151},{"title":157,"path":158,"stem":159,"icon":151},"算术运算符","\u002Fch02\u002Fpart2\u002Farithmetic_operator","ch02\u002Fpart2\u002Farithmetic_operator",{"title":161,"path":162,"stem":163,"icon":151},"赋值运算符","\u002Fch02\u002Fpart2\u002Fassignment_operator","ch02\u002Fpart2\u002Fassignment_operator",{"title":165,"path":166,"stem":167,"icon":151},"位运算符（选读）","\u002Fch02\u002Fpart2\u002Fbit_operator","ch02\u002Fpart2\u002Fbit_operator",{"title":169,"path":170,"stem":171,"icon":151},"关系运算符","\u002Fch02\u002Fpart2\u002Fcomparison_operator","ch02\u002Fpart2\u002Fcomparison_operator",{"title":173,"path":174,"stem":175,"icon":151},"算术类型隐式转换","\u002Fch02\u002Fpart2\u002Fimplicit_conversion","ch02\u002Fpart2\u002Fimplicit_conversion",{"title":177,"path":178,"stem":179,"icon":151},"自增减运算符","\u002Fch02\u002Fpart2\u002Fincdec_operator","ch02\u002Fpart2\u002Fincdec_operator",{"title":181,"path":182,"stem":183,"icon":151},"逻辑运算符","\u002Fch02\u002Fpart2\u002Flogical_operator","ch02\u002Fpart2\u002Flogical_operator",{"title":185,"path":186,"stem":187,"icon":151},"其它常用运算符","\u002Fch02\u002Fpart2\u002Fother_operator","ch02\u002Fpart2\u002Fother_operator",{"title":189,"icon":190,"path":191,"stem":192,"children":193},"第 3 部分 控制成分","i-lucide-git-branch","\u002Fch02\u002Fpart3","ch02\u002Fpart3\u002Findex",[194,195,199,203,207,211,215,219,223],{"title":189,"path":191,"stem":192,"icon":190},{"title":196,"path":197,"stem":198,"icon":190},"复合语句","\u002Fch02\u002Fpart3\u002Fcompound_statement","ch02\u002Fpart3\u002Fcompound_statement",{"title":200,"path":201,"stem":202,"icon":190},"for 语句","\u002Fch02\u002Fpart3\u002Ffor_statement","ch02\u002Fpart3\u002Ffor_statement",{"title":204,"path":205,"stem":206,"icon":190},"if 语句","\u002Fch02\u002Fpart3\u002Fif_statement","ch02\u002Fpart3\u002Fif_statement",{"title":208,"path":209,"stem":210,"icon":190},"跳转语句","\u002Fch02\u002Fpart3\u002Fjump_statement","ch02\u002Fpart3\u002Fjump_statement",{"title":212,"path":213,"stem":214,"icon":190},"空语句","\u002Fch02\u002Fpart3\u002Fnull_statement","ch02\u002Fpart3\u002Fnull_statement",{"title":216,"path":217,"stem":218,"icon":190},"作用域","\u002Fch02\u002Fpart3\u002Fscope","ch02\u002Fpart3\u002Fscope",{"title":220,"path":221,"stem":222,"icon":190},"switch 语句","\u002Fch02\u002Fpart3\u002Fswitch_statement","ch02\u002Fpart3\u002Fswitch_statement",{"title":224,"path":225,"stem":226,"icon":190},"while 语句","\u002Fch02\u002Fpart3\u002Fwhile_statement","ch02\u002Fpart3\u002Fwhile_statement",{"title":93,"path":228,"stem":229,"icon":102},"\u002Fch02\u002Fsummary","ch02\u002Fsummary",{"title":231,"icon":232,"path":233,"stem":234,"children":235},"第三章 过程式编程","i-lucide-function-square","\u002Fch03","ch03",[236,239,243,247,251,255,259,263,267],{"title":231,"path":233,"stem":237,"icon":238},"ch03\u002Findex","i-lucide-square-function",{"title":240,"path":241,"stem":242,"icon":232},"函数","\u002Fch03\u002Ffunction","ch03\u002Ffunction",{"title":244,"path":245,"stem":246,"icon":232},"函数的定义、声明和调用","\u002Fch03\u002Ffunction_definition","ch03\u002Ffunction_definition",{"title":248,"path":249,"stem":250,"icon":232},"函数的执行","\u002Fch03\u002Ffunction_execution","ch03\u002Ffunction_execution",{"title":252,"path":253,"stem":254,"icon":232},"初识函数","\u002Fch03\u002Ffunction_glance","ch03\u002Ffunction_glance",{"title":256,"path":257,"stem":258,"icon":232},"递归","\u002Fch03\u002Frecursion","ch03\u002Frecursion",{"title":260,"path":261,"stem":262,"icon":232},"重新认识 C++ 程序","\u002Fch03\u002Freview_cpp","ch03\u002Freview_cpp",{"title":264,"path":265,"stem":266,"icon":232},"再谈作用域","\u002Fch03\u002Fscope_again","ch03\u002Fscope_again",{"title":93,"path":268,"stem":269,"icon":232},"\u002Fch03\u002Fsummary","ch03\u002Fsummary",{"title":271,"icon":272,"path":273,"stem":274,"children":275},"第四章 POD 类型与结构","i-lucide-layers","\u002Fch04","ch04",[276,278,301,316,320,338,365,392,407,410],{"title":271,"path":273,"stem":277,"icon":272},"ch04\u002Findex",{"title":279,"icon":280,"path":281,"stem":282,"children":283},"数组","i-lucide-grid","\u002Fch04\u002Farray","ch04\u002Farray\u002Findex",[284,285,289,293,297],{"title":279,"path":281,"stem":282,"icon":280},{"title":286,"path":287,"stem":288,"icon":280},"二维数组","\u002Fch04\u002Farray\u002F2d_array","ch04\u002Farray\u002F2d_array",{"title":290,"path":291,"stem":292,"icon":280},"数组的定义和初始化","\u002Fch04\u002Farray\u002Farray_init","ch04\u002Farray\u002Farray_init",{"title":294,"path":295,"stem":296,"icon":280},"数组的用途","\u002Fch04\u002Farray\u002Farray_usage","ch04\u002Farray\u002Farray_usage",{"title":298,"path":299,"stem":300,"icon":280},"C 风格字符串","\u002Fch04\u002Farray\u002Fc_string","ch04\u002Farray\u002Fc_string",{"title":302,"icon":303,"path":304,"stem":305,"children":306},"迁移到 C 语言","i-lucide-arrow-right-left","\u002Fch04\u002Fcompare_with_c","ch04\u002Fcompare_with_c\u002Findex",[307,308,312],{"title":302,"path":304,"stem":305,"icon":303},{"title":309,"path":310,"stem":311,"icon":303},"需要注意的 C 特性","\u002Fch04\u002Fcompare_with_c\u002Fc_feature","ch04\u002Fcompare_with_c\u002Fc_feature",{"title":313,"path":314,"stem":315,"icon":303},"C 输入输出","\u002Fch04\u002Fcompare_with_c\u002Fc_io","ch04\u002Fcompare_with_c\u002Fc_io",{"title":317,"path":318,"stem":319,"icon":272},"枚举","\u002Fch04\u002Fenum","ch04\u002Fenum",{"title":321,"path":322,"stem":323,"children":324,"icon":326},"输入输出成分","\u002Fch04\u002Fio","ch04\u002Fio\u002Findex",[325,327,330,334],{"title":321,"path":322,"stem":323,"icon":326},"i-lucide-terminal",{"title":77,"path":328,"stem":329,"icon":326},"\u002Fch04\u002Fio\u002Finput","ch04\u002Fio\u002Finput",{"title":331,"path":332,"stem":333,"icon":326},"输入失败状态","\u002Fch04\u002Fio\u002Finput_fail","ch04\u002Fio\u002Finput_fail",{"title":335,"path":336,"stem":337,"icon":326},"输出","\u002Fch04\u002Fio\u002Foutput","ch04\u002Fio\u002Foutput",{"title":339,"icon":340,"path":341,"stem":342,"children":343},"链表","i-lucide-list","\u002Fch04\u002Flist","ch04\u002Flist\u002Findex",[344,345,349,353,357,361],{"title":339,"path":341,"stem":342,"icon":340},{"title":346,"path":347,"stem":348,"icon":340},"new[] 和 delete[]","\u002Fch04\u002Flist\u002Farr_new_del","ch04\u002Flist\u002Farr_new_del",{"title":350,"path":351,"stem":352,"icon":340},"链表的增删","\u002Fch04\u002Flist\u002Flist_add_del","ch04\u002Flist\u002Flist_add_del",{"title":354,"path":355,"stem":356,"icon":340},"链表的构建","\u002Fch04\u002Flist\u002Flist_construct","ch04\u002Flist\u002Flist_construct",{"title":358,"path":359,"stem":360,"icon":340},"安全性","\u002Fch04\u002Flist\u002Fsafety","ch04\u002Flist\u002Fsafety",{"title":362,"path":363,"stem":364,"icon":340},"存储期","\u002Fch04\u002Flist\u002Fstorage_duration","ch04\u002Flist\u002Fstorage_duration",{"title":366,"path":367,"stem":368,"children":369,"icon":371},"指针","\u002Fch04\u002Fpointer","ch04\u002Fpointer\u002Findex",[370,372,376,380,384,388],{"title":366,"path":367,"stem":368,"icon":371},"i-lucide-dot",{"title":373,"path":374,"stem":375,"icon":371},"何为指针","\u002Fch04\u002Fpointer\u002Fpointer","ch04\u002Fpointer\u002Fpointer",{"title":377,"path":378,"stem":379,"icon":371},"指针和数组","\u002Fch04\u002Fpointer\u002Fpointer_and_array","ch04\u002Fpointer\u002Fpointer_and_array",{"title":381,"path":382,"stem":383,"icon":371},"指针的定义 Ⅰ","\u002Fch04\u002Fpointer\u002Fpointer_def","ch04\u002Fpointer\u002Fpointer_def",{"title":385,"path":386,"stem":387,"icon":371},"指针的定义 Ⅱ","\u002Fch04\u002Fpointer\u002Fpointer_def_2","ch04\u002Fpointer\u002Fpointer_def_2",{"title":389,"path":390,"stem":391,"icon":371},"指针的简单使用","\u002Fch04\u002Fpointer\u002Fpointer_usage","ch04\u002Fpointer\u002Fpointer_usage",{"title":393,"path":394,"stem":395,"children":396,"icon":398},"结构体","\u002Fch04\u002Fstruct","ch04\u002Fstruct\u002Findex",[397,399,403],{"title":393,"path":394,"stem":395,"icon":398},"i-lucide-box",{"title":400,"path":401,"stem":402,"icon":398},"结构体的定义","\u002Fch04\u002Fstruct\u002Fstruct_def","ch04\u002Fstruct\u002Fstruct_def",{"title":404,"path":405,"stem":406,"icon":398},"结构体的使用","\u002Fch04\u002Fstruct\u002Fstruct_usage","ch04\u002Fstruct\u002Fstruct_usage",{"title":93,"path":408,"stem":409,"icon":272},"\u002Fch04\u002Fsummary","ch04\u002Fsummary",{"title":411,"path":412,"stem":413,"icon":272},"联合体","\u002Fch04\u002Funion","ch04\u002Funion",{"title":415,"icon":416,"path":417,"stem":418,"children":419},"第五章 初探面向对象","i-lucide-copy","\u002Fch05","ch05",[420,422,426,430,434,438,442,446,450,454],{"title":415,"path":417,"stem":421,"icon":416},"ch05\u002Findex",{"title":423,"path":424,"stem":425,"icon":416},"构造函数","\u002Fch05\u002Fconstructor","ch05\u002Fconstructor",{"title":427,"path":428,"stem":429,"icon":416},"复制构造函数","\u002Fch05\u002Fcopy_constructor","ch05\u002Fcopy_constructor",{"title":431,"path":432,"stem":433,"icon":416},"预置构造函数","\u002Fch05\u002Fdefaulted_constructor","ch05\u002Fdefaulted_constructor",{"title":435,"path":436,"stem":437,"icon":416},"例子：简单的字符串","\u002Fch05\u002Feasy_string","ch05\u002Feasy_string",{"title":439,"path":440,"stem":441,"icon":416},"收尾工作","\u002Fch05\u002Fmisc","ch05\u002Fmisc",{"title":443,"path":444,"stem":445,"icon":416},"重载","\u002Fch05\u002Foverload","ch05\u002Foverload",{"title":447,"path":448,"stem":449,"icon":416},"引用","\u002Fch05\u002Freference","ch05\u002Freference",{"title":451,"path":452,"stem":453,"icon":416},"浅复制与深复制","\u002Fch05\u002Fshallow_deep_copy","ch05\u002Fshallow_deep_copy",{"title":93,"path":455,"stem":456,"icon":416},"\u002Fch05\u002Fsummary","ch05\u002Fsummary",{"title":458,"icon":459,"path":460,"stem":461,"children":462},"第六章 运算符重载","i-lucide-component","\u002Fch06","ch06",[463,465,469,473,477,481,485,489,493,497,501,504],{"title":458,"path":460,"stem":464,"icon":459},"ch06\u002Findex",{"title":466,"path":467,"stem":468,"icon":459},"赋值运算符重载","\u002Fch06\u002Fassignment_overload","ch06\u002Fassignment_overload",{"title":470,"path":471,"stem":472,"icon":459},"赋值与初始化","\u002Fch06\u002Fassignment_vs_construct","ch06\u002Fassignment_vs_construct",{"title":474,"path":475,"stem":476,"icon":459},"类型转换重载","\u002Fch06\u002Fcast_overload","ch06\u002Fcast_overload",{"title":478,"path":479,"stem":480,"icon":459},"只读成员函数","\u002Fch06\u002Fconst_member_function","ch06\u002Fconst_member_function",{"title":482,"path":483,"stem":484,"icon":459},"友元","\u002Fch06\u002Ffriend","ch06\u002Ffriend",{"title":486,"path":487,"stem":488,"icon":459},"类外定义成员函数","\u002Fch06\u002Fnoninline_member_function","ch06\u002Fnoninline_member_function",{"title":490,"path":491,"stem":492,"icon":459},"非成员的运算符重载","\u002Fch06\u002Fnonmember_operator","ch06\u002Fnonmember_operator",{"title":494,"path":495,"stem":496,"icon":459},"特殊运算符重载","\u002Fch06\u002Fspecial_operator_overload","ch06\u002Fspecial_operator_overload",{"title":498,"path":499,"stem":500,"icon":459},"静态成员","\u002Fch06\u002Fstatic_member","ch06\u002Fstatic_member",{"title":93,"path":502,"stem":503,"icon":459},"\u002Fch06\u002Fsummary","ch06\u002Fsummary",{"title":505,"path":506,"stem":507,"icon":459},"`this` 指针","\u002Fch06\u002Fthis","ch06\u002Fthis",{"title":509,"path":510,"stem":511,"children":512,"icon":190},"第七章 继承与多态","\u002Fch07","ch07\u002Findex",[513,514,541,545,549,580],{"title":509,"path":510,"stem":511,"icon":190},{"title":515,"icon":516,"path":517,"stem":518,"children":519},"继承关系","i-lucide-share","\u002Fch07\u002Finheritance","ch07\u002Finheritance\u002Findex",[520,521,525,529,533,537],{"title":515,"path":517,"stem":518,"icon":516},{"title":522,"path":523,"stem":524,"icon":516},"关于成员名","\u002Fch07\u002Finheritance\u002Fabout_member_name","ch07\u002Finheritance\u002Fabout_member_name",{"title":526,"path":527,"stem":528,"icon":516},"派生类的构造","\u002Fch07\u002Finheritance\u002Fderived_constructor","ch07\u002Finheritance\u002Fderived_constructor",{"title":530,"path":531,"stem":532,"icon":516},"继承中的隐式转换","\u002Fch07\u002Finheritance\u002Fimplicit_cast_in_inheritance","ch07\u002Finheritance\u002Fimplicit_cast_in_inheritance",{"title":534,"path":535,"stem":536,"icon":516},"其它小问题","\u002Fch07\u002Finheritance\u002Fmisc","ch07\u002Finheritance\u002Fmisc",{"title":538,"path":539,"stem":540,"icon":516},"保护成员","\u002Fch07\u002Finheritance\u002Fprotected_member","ch07\u002Finheritance\u002Fprotected_member",{"title":542,"path":543,"stem":544,"icon":190},"多重继承","\u002Fch07\u002Fmi","ch07\u002Fmi",{"title":546,"path":547,"stem":548,"icon":190},"简单的对象关系","\u002Fch07\u002Fobject_relationships","ch07\u002Fobject_relationships",{"title":550,"icon":551,"path":552,"stem":553,"children":554},"多态","i-lucide-refresh","\u002Fch07\u002Fpolymorphism","ch07\u002Fpolymorphism\u002Findex",[555,556,560,564,568,572,576],{"title":550,"path":552,"stem":553,"icon":551},{"title":557,"path":558,"stem":559,"icon":551},"抽象类","\u002Fch07\u002Fpolymorphism\u002Fabstract_class","ch07\u002Fpolymorphism\u002Fabstract_class",{"title":561,"path":562,"stem":563,"icon":551},"C++ 风格类型转换","\u002Fch07\u002Fpolymorphism\u002Fcpp_cast","ch07\u002Fpolymorphism\u002Fcpp_cast",{"title":565,"path":566,"stem":567,"icon":551},"`override` 与 `final`","\u002Fch07\u002Fpolymorphism\u002Foverride_and_final","ch07\u002Fpolymorphism\u002Foverride_and_final",{"title":569,"path":570,"stem":571,"icon":551},"RTTI","\u002Fch07\u002Fpolymorphism\u002Frtti","ch07\u002Fpolymorphism\u002Frtti",{"title":573,"path":574,"stem":575,"icon":551},"虚析构函数","\u002Fch07\u002Fpolymorphism\u002Fvirtual_destructor","ch07\u002Fpolymorphism\u002Fvirtual_destructor",{"title":577,"path":578,"stem":579,"icon":551},"虚函数","\u002Fch07\u002Fpolymorphism\u002Fvirtual_function","ch07\u002Fpolymorphism\u002Fvirtual_function",{"title":93,"path":581,"stem":582,"icon":190},"\u002Fch07\u002Fsummary","ch07\u002Fsummary",{"title":584,"icon":585,"path":586,"stem":587,"children":588},"第八章 模板基础","i-lucide-layout-template","\u002Fch08","ch08",[589,591,595,599,603,607,646],{"title":584,"path":586,"stem":590,"icon":585},"ch08\u002Findex",{"title":592,"path":593,"stem":594,"icon":585},"类模板","\u002Fch08\u002Fclass_template","ch08\u002Fclass_template",{"title":596,"path":597,"stem":598,"icon":585},"默认实参","\u002Fch08\u002Fdefault_argument","ch08\u002Fdefault_argument",{"title":600,"path":601,"stem":602,"icon":585},"函数模板","\u002Fch08\u002Ffunction_template","ch08\u002Ffunction_template",{"title":604,"path":605,"stem":606,"icon":585},"非类型模板参数","\u002Fch08\u002Fnontype_template_param","ch08\u002Fnontype_template_param",{"title":608,"icon":609,"path":610,"stem":611,"children":612},"STL 容器和迭代器","i-lucide-container","\u002Fch08\u002Fstl_containers","ch08\u002Fstl_containers\u002Findex",[613,614,618,622,626,630,634,638,642],{"title":608,"path":610,"stem":611,"icon":609},{"title":615,"path":616,"stem":617,"icon":609},"容器适配器","\u002Fch08\u002Fstl_containers\u002Fadaptors","ch08\u002Fstl_containers\u002Fadaptors",{"title":619,"path":620,"stem":621,"icon":609},"迭代器的概念","\u002Fch08\u002Fstl_containers\u002Fiterator_concept","ch08\u002Fstl_containers\u002Fiterator_concept",{"title":623,"path":624,"stem":625,"icon":609},"初识迭代器","\u002Fch08\u002Fstl_containers\u002Fiterator_glance","ch08\u002Fstl_containers\u002Fiterator_glance",{"title":627,"path":628,"stem":629,"icon":609},"迭代器的用途","\u002Fch08\u002Fstl_containers\u002Fiterator_usage","ch08\u002Fstl_containers\u002Fiterator_usage",{"title":631,"path":632,"stem":633,"icon":609},"`std::map`","\u002Fch08\u002Fstl_containers\u002Fmap","ch08\u002Fstl_containers\u002Fmap",{"title":635,"path":636,"stem":637,"icon":609},"其它顺序容器","\u002Fch08\u002Fstl_containers\u002Fother_sequence","ch08\u002Fstl_containers\u002Fother_sequence",{"title":639,"path":640,"stem":641,"icon":609},"`std::set`","\u002Fch08\u002Fstl_containers\u002Fset","ch08\u002Fstl_containers\u002Fset",{"title":643,"path":644,"stem":645,"icon":609},"`std::vector`","\u002Fch08\u002Fstl_containers\u002Fvector","ch08\u002Fstl_containers\u002Fvector",{"title":93,"path":647,"stem":648,"icon":585},"\u002Fch08\u002Fsummary","ch08\u002Fsummary",{"title":650,"icon":651,"path":652,"stem":653,"children":654},"第九章 链接","i-lucide-link","\u002Fch09","ch09",[655,657,661,665,669,673,677,681],{"title":650,"path":652,"stem":656,"icon":651},"ch09\u002Findex",{"title":658,"path":659,"stem":660,"icon":651},"C 中的链接","\u002Fch09\u002Fc_linking","ch09\u002Fc_linking",{"title":662,"path":663,"stem":664,"icon":651},"多文件编译实践","\u002Fch09\u002Fcompile_multiple_files","ch09\u002Fcompile_multiple_files",{"title":666,"path":667,"stem":668,"icon":651},"模板中的友元","\u002Fch09\u002Ffriend_in_template","ch09\u002Ffriend_in_template",{"title":670,"path":671,"stem":672,"icon":651},"内联","\u002Fch09\u002Finline","ch09\u002Finline",{"title":674,"path":675,"stem":676,"icon":651},"单一定义原则","\u002Fch09\u002Fodr","ch09\u002Fodr",{"title":678,"path":679,"stem":680,"icon":651},"符号和连接","\u002Fch09\u002Fsymbol_and_linkage","ch09\u002Fsymbol_and_linkage",{"title":682,"path":683,"stem":684,"icon":651},"模板的链接","\u002Fch09\u002Ftemplate_linking","ch09\u002Ftemplate_linking",{"title":686,"icon":687,"path":688,"stem":689,"children":690},"第十章 常用库介绍 \u003CBadge type=\"warning\" text=\"TBC\" \u002F>","i-lucide-hard-drive","\u002Fch10","ch10",[691,694,717,732,736,740],{"title":692,"path":688,"stem":693,"icon":687},"第十章 常用库介绍","ch10\u002Findex",{"title":695,"icon":696,"path":697,"stem":698,"children":699},"代数数据类型","i-lucide-shapes","\u002Fch10\u002Fadt","ch10\u002Fadt\u002Findex",[700,701,705,709,713],{"title":695,"path":697,"stem":698,"icon":696},{"title":702,"path":703,"stem":704,"icon":696},"顶类型 `std::any`","\u002Fch10\u002Fadt\u002Fany","ch10\u002Fadt\u002Fany",{"title":706,"path":707,"stem":708,"icon":696},"底类型","\u002Fch10\u002Fadt\u002Fnoreturn","ch10\u002Fadt\u002Fnoreturn",{"title":710,"path":711,"stem":712,"icon":696},"通用积类型 `std::tuple`","\u002Fch10\u002Fadt\u002Ftuple","ch10\u002Fadt\u002Ftuple",{"title":714,"path":715,"stem":716,"icon":696},"通用和类型 `std::variant`","\u002Fch10\u002Fadt\u002Fvariant","ch10\u002Fadt\u002Fvariant",{"title":718,"icon":719,"path":720,"stem":721,"children":722},"文件读写","i-lucide-file-text","\u002Fch10\u002Ffile_io","ch10\u002Ffile_io\u002Findex",[723,724,728],{"title":718,"path":720,"stem":721,"icon":719},{"title":725,"path":726,"stem":727,"icon":719},"C 风格输入输出","\u002Fch10\u002Ffile_io\u002Fc_io","ch10\u002Ffile_io\u002Fc_io",{"title":729,"path":730,"stem":731,"icon":719},"流式输入输出","\u002Fch10\u002Ffile_io\u002Fstream","ch10\u002Ffile_io\u002Fstream",{"title":733,"path":734,"stem":735,"icon":687},"文件系统","\u002Fch10\u002Ffilesystem","ch10\u002Ffilesystem",{"title":737,"path":738,"stem":739,"icon":687},"伪随机数生成","\u002Fch10\u002Frandom","ch10\u002Frandom",{"title":741,"path":742,"stem":743,"children":744,"icon":746},"移动语义与智能指针","\u002Fch10\u002Fsmart_pointer","ch10\u002Fsmart_pointer\u002Findex",[745,747,751,755,759,763],{"title":741,"path":742,"stem":743,"icon":746},"i-lucide-pointer",{"title":748,"path":749,"stem":750,"icon":746},"`std::move` 与转发引用","\u002Fch10\u002Fsmart_pointer\u002Fmove_and_forward","ch10\u002Fsmart_pointer\u002Fmove_and_forward",{"title":752,"path":753,"stem":754,"icon":746},"所有权","\u002Fch10\u002Fsmart_pointer\u002Fownership","ch10\u002Fsmart_pointer\u002Fownership",{"title":756,"path":757,"stem":758,"icon":746},"右值引用","\u002Fch10\u002Fsmart_pointer\u002Frvalue_reference","ch10\u002Fsmart_pointer\u002Frvalue_reference",{"title":760,"path":761,"stem":762,"icon":746},"`std::shared_ptr`","\u002Fch10\u002Fsmart_pointer\u002Fshared_ptr","ch10\u002Fsmart_pointer\u002Fshared_ptr",{"title":764,"path":765,"stem":766,"icon":746},"特殊成员函数","\u002Fch10\u002Fsmart_pointer\u002Fspecial_member_function","ch10\u002Fsmart_pointer\u002Fspecial_member_function",{"title":768,"icon":769,"path":770,"stem":771,"children":772},"第十一章 函数式编程","i-lucide-sparkles","\u002Fch11","ch11",[773,775,794,821,825],{"title":768,"path":770,"stem":774,"icon":769},"ch11\u002Findex",{"title":776,"icon":777,"path":778,"stem":779,"children":780},"语法进阶","i-lucide-graduation-cap","\u002Fch11\u002Fadvanced","ch11\u002Fadvanced\u002Findex",[781,782,786,790],{"title":776,"path":778,"stem":779,"icon":777},{"title":783,"path":784,"stem":785,"icon":777},"实参依赖查找","\u002Fch11\u002Fadvanced\u002Fadl","ch11\u002Fadvanced\u002Fadl",{"title":787,"path":788,"stem":789,"icon":777},"可调用","\u002Fch11\u002Fadvanced\u002Fcallable","ch11\u002Fadvanced\u002Fcallable",{"title":791,"path":792,"stem":793,"icon":777},"预置比较","\u002Fch11\u002Fadvanced\u002Fdefaulted_compare","ch11\u002Fadvanced\u002Fdefaulted_compare",{"title":795,"icon":796,"path":797,"stem":798,"children":799},"语法基础","i-lucide-book-text","\u002Fch11\u002Fgrammar","ch11\u002Fgrammar\u002Findex",[800,801,805,809,813,817],{"title":795,"path":797,"stem":798,"icon":796},{"title":802,"path":803,"stem":804,"icon":796},"闭包","\u002Fch11\u002Fgrammar\u002Fclosure","ch11\u002Fgrammar\u002Fclosure",{"title":806,"path":807,"stem":808,"icon":796},"函数也即对象","\u002Fch11\u002Fgrammar\u002Ffunction_as_object","ch11\u002Fgrammar\u002Ffunction_as_object",{"title":810,"path":811,"stem":812,"icon":796},"高阶函数","\u002Fch11\u002Fgrammar\u002Fhigher_order_function","ch11\u002Fgrammar\u002Fhigher_order_function",{"title":814,"path":815,"stem":816,"icon":796},"Lambda 表达式","\u002Fch11\u002Fgrammar\u002Flambda","ch11\u002Fgrammar\u002Flambda",{"title":818,"path":819,"stem":820,"icon":796},"Lambda 表达式捕获","\u002Fch11\u002Fgrammar\u002Flambda_capture","ch11\u002Fgrammar\u002Flambda_capture",{"title":822,"path":823,"stem":824,"icon":769},"`std::sort`","\u002Fch11\u002Fstd_sort","ch11\u002Fstd_sort",{"title":826,"icon":827,"path":828,"stem":829,"children":830},"STL 算法","i-lucide-sort-asc","\u002Fch11\u002Fstl_algorithms","ch11\u002Fstl_algorithms\u002Findex",[831,832,836,840,844,848,852,856,860],{"title":826,"path":828,"stem":829,"icon":827},{"title":833,"path":834,"stem":835,"icon":827},"迁移到 STLv1","\u002Fch11\u002Fstl_algorithms\u002Fcompare_with_legacy","ch11\u002Fstl_algorithms\u002Fcompare_with_legacy",{"title":837,"path":838,"stem":839,"icon":827},"复制","\u002Fch11\u002Fstl_algorithms\u002Fcopy","ch11\u002Fstl_algorithms\u002Fcopy",{"title":841,"path":842,"stem":843,"icon":827},"筛选","\u002Fch11\u002Fstl_algorithms\u002Ffilter","ch11\u002Fstl_algorithms\u002Ffilter",{"title":845,"path":846,"stem":847,"icon":827},"其它算法","\u002Fch11\u002Fstl_algorithms\u002Fothers","ch11\u002Fstl_algorithms\u002Fothers",{"title":849,"path":850,"stem":851,"icon":827},"初识范围","\u002Fch11\u002Fstl_algorithms\u002Frange","ch11\u002Fstl_algorithms\u002Frange",{"title":853,"path":854,"stem":855,"icon":827},"归约","\u002Fch11\u002Fstl_algorithms\u002Freduce","ch11\u002Fstl_algorithms\u002Freduce",{"title":857,"path":858,"stem":859,"icon":827},"排序","\u002Fch11\u002Fstl_algorithms\u002Fsort","ch11\u002Fstl_algorithms\u002Fsort",{"title":861,"path":862,"stem":863,"icon":827},"变换","\u002Fch11\u002Fstl_algorithms\u002Ftransform","ch11\u002Fstl_algorithms\u002Ftransform",{"title":865,"icon":866,"path":867,"stem":868,"children":869},"第十二章 模板","i-lucide-git-fork","\u002Fch12","ch12",[870,873,877,881,885],{"title":871,"path":867,"stem":872,"icon":866},"第十二章 模板进阶","ch12\u002Findex",{"title":874,"path":875,"stem":876},"C++20 概念","\u002Fch12\u002Fconcepts","ch12\u002Fconcepts",{"title":878,"path":879,"stem":880},"模板元编程","\u002Fch12\u002Fmetaprogramming","ch12\u002Fmetaprogramming",{"title":882,"path":883,"stem":884},"模板特化与偏特化","\u002Fch12\u002Fspecialization","ch12\u002Fspecialization",{"title":886,"icon":887,"path":888,"stem":889,"children":890},"静态派发","i-lucide-route","\u002Fch12\u002Fstatic_dispatch","ch12\u002Fstatic_dispatch\u002Findex",[891,892,896],{"title":886,"path":888,"stem":889},{"title":893,"path":894,"stem":895},"定制点","\u002Fch12\u002Fstatic_dispatch\u002Fcustomize_point","ch12\u002Fstatic_dispatch\u002Fcustomize_point",{"title":897,"path":898,"stem":899},"类型擦除","\u002Fch12\u002Fstatic_dispatch\u002Ftype_erasure","ch12\u002Fstatic_dispatch\u002Ftype_erasure",{"title":901,"path":902,"stem":903,"icon":6},"后记","\u002Fpostscript","postscript",{"title":905,"path":906,"stem":907,"icon":908},"技术信息","\u002Ftechnical_info","technical_info","i-lucide-info",{"id":910,"title":13,"body":911,"description":13,"extension":2968,"links":2969,"meta":2970,"navigation":2971,"path":14,"seo":2972,"stem":15,"__hash__":2973},"docs\u002Fappendix\u002Fcli.md",{"type":912,"value":913,"toc":2955},"minimark",[914,917,922,926,933,945,948,951,968,981,986,996,1006,1009,1015,1025,1038,1050,1068,1240,1251,1267,1272,1297,1458,1462,1465,1467,1474,1476,1487,1514,1527,1541,1551,1553,1577,1579,1600,1610,1612,1615,1680,1699,1702,1713,1717,1726,1735,1738,1743,1753,1821,1824,1830,1843,1848,1854,1859,1862,1883,1891,1896,1922,1925,1928,1941,1951,1956,1961,1988,1997,2002,2015,2030,2043,2049,2054,2100,2106,2111,2124,2127,2131,2157,2166,2244,2250,2253,2255,2272,2277,2349,2352,2357,2365,2370,2378,2384,2437,2439,2443,2457,2462,2474,2480,2485,2515,2525,2530,2562,2566,2603,2617,2623,2661,2671,2680,2687,2693,2710,2748,2783,2790,2795,2807,2837,2841,2844,2857,2878,2895,2901,2906,2915,2933,2943,2948,2951],[915,916,13],"h1",{"id":13},[918,919,921],"h2",{"id":920},"gui-与-cli","GUI 与 CLI",[923,924,925],"p",{},"大部分的操作系统都是默认以图形界面（Graphical User Interface, GUI）启动的，从而使得用户可以用显示屏看到五颜六色的窗口，用键盘和鼠标来进行大量的操作。但是在早期计算机并不发达的年代，使用者只能在一个由纯文本组成的界面中，使用键盘向其中键入“命令”，然后得到计算机显示的结果。大概的样子是长成这样：",[923,927,928],{},[929,930],"img",{"alt":931,"src":932},"","https:\u002F\u002Fs1.ax1x.com\u002F2022\u002F06\u002F29\u002FjnmFZd.png",[923,934,935,936,940,941,944],{},"实际上这个过程并不陌生，截止至目前为止我们演示的所有 C++ 程序都是基于命令行界面的：",[937,938,939],"code",{},"std::cin"," 读取键盘的输入，然后 ",[937,942,943],{},"std::cout"," 把结果输出到某个地方——只不过，这些输入输出大多是通过 GUI 显示的。那么想要退回去使用比较古早的 CLI，则需要用到终端模拟器（Terminal Emulator）。在 Windows 上，可以通过从开始菜单启动“命令提示符”程序来启动终端模拟器，而在 macOS 上则是“终端”应用程序：",[923,946,947],{},"图",[918,949,950],{"id":950},"壳层程序",[923,952,953,954,957,958,961,962,964,965,967],{},"终端模拟器中，你必须使用命令行界面来操作。基本上，你只能做两件事：通过键盘键入内容，通过终端模拟器上的文字来阅读内容。一般地，终端模拟器启动时会打开一个称为“壳层”（Shell）的程序来帮助你操作。这个程序可以源源不断地接受键盘的输入（被称作“命令”），然后分析这个输入是在做什么，然后做一些事情，这样不断地重复。比如你在其中键入了 ",[937,955,956],{},"echo Hello"," 这个命令，然后壳层程序就开始分析这个命令的含义：得知其含义是“输出 ",[937,959,960],{},"Hello"," 到屏幕上”，然后就确切地去做这件事情：将 ",[937,963,960],{}," 输出。下面演示了主流操作系统下的命令行界面在接受 ",[937,966,956],{}," 命令时的行为：",[923,969,970,971,974,975,977,978,980],{},"在 Windows 上，这个壳层程序叫做 ",[937,972,973],{},"cmd.exe","。当你向其中输入 ",[937,976,956],{}," 并按下回车时，壳层程序会输出 ",[937,979,960],{},"，然后再次等待你的下一个命令：",[923,982,983],{},[929,984],{"alt":931,"src":985},"https:\u002F\u002Fz3.ax1x.com\u002F2021\u002F08\u002F29\u002FhJA3TI.png",[923,987,988,989,974,992,977,994,980],{},"在 GNU\u002FLinux 上，这个壳层程序一般是 ",[937,990,991],{},"bash",[937,993,956],{},[937,995,960],{},[923,997,998,999,974,1002,977,1004,980],{},"在 macOS 上，这个壳层程序则是 ",[937,1000,1001],{},"zsh",[937,1003,956],{},[937,1005,960],{},[918,1007,1008],{"id":1008},"程序执行和命令行参数",[923,1010,1011,1012,1014],{},"我现在来解释一下 ",[937,1013,956],{}," 这个命令对于壳层的意义。简单来说，每一个命令都是这样形式的：",[1016,1017,1018],"sdsc",{},[923,1019,1020,1021],{},"程序名 ",[1022,1023,1024],"span",{},"参数1 参数2 ...",[923,1026,1027,1028,1031,1032,1034,1035,1037],{},"每一个命令按空格分成若干段，最重要的是第一段，称作“程序名”。程序名指定了一个程序：壳层会在 CLI 中启动这个程序，然后将输入输出的控制权交给它。也就是说，系统中存在一个名为 ",[937,1029,1030],{},"echo"," 的程序，当执行 ",[937,1033,956],{}," 时，壳层会启动这个 ",[937,1036,1030],{}," 程序。",[1039,1040,1041],"blockquote",{},[923,1042,1043,1044,1046,1047,1049],{},"上面的例子在 Windows 下是错误的，对于一些终端如 ",[937,1045,1001],{}," 等也是错误的。",[937,1048,1030],{}," 在这些情形下是作为壳层的内置命令而非外部程序运行的。",[923,1051,1052,1053,1055,1056,1058,1059,1061,1062,1064,1065,1067],{},"除命令的第一段外，剩下的部分称为命令的“参数”。这些参数将在程序启动时通过一种特别的方式传入程序，而程序可以通过一些方法获得这些参数。比如，",[937,1054,1030],{}," 程序需要输出这个“参数”，从而让 ",[937,1057,956],{}," 启动 ",[937,1060,1030],{}," 程序后可以输出 ",[937,1063,960],{},"。为了说明如何做到这一点，我将写一个超级简化版的 ",[937,1066,1030],{}," 程序的源码：",[1069,1070,1074],"pre",{"className":1071,"code":1072,"language":1073,"meta":931,"style":931},"language-cpp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F echo.cpp 超级简化版 echo 源码\n#include \u003Ciostream>\nusing namespace std;\nint main(int argc, char** argv) {\n    if (argc == 1) {\n        cout \u003C\u003C endl;\n    } else {\n        cout \u003C\u003C argv[1] \u003C\u003C endl;\n    }\n}\n","cpp",[937,1075,1076,1084,1102,1120,1154,1177,1192,1203,1228,1234],{"__ignoreMap":931},[1022,1077,1080],{"class":1078,"line":1079},"line",1,[1022,1081,1083],{"class":1082},"sHwdD","\u002F\u002F echo.cpp 超级简化版 echo 源码\n",[1022,1085,1087,1091,1095,1099],{"class":1078,"line":1086},2,[1022,1088,1090],{"class":1089},"s7zQu","#include",[1022,1092,1094],{"class":1093},"sMK4o"," \u003C",[1022,1096,1098],{"class":1097},"sfazB","iostream",[1022,1100,1101],{"class":1093},">\n",[1022,1103,1105,1109,1113,1117],{"class":1078,"line":1104},3,[1022,1106,1108],{"class":1107},"sbssI","using",[1022,1110,1112],{"class":1111},"spNyl"," namespace",[1022,1114,1116],{"class":1115},"sBMFI"," std",[1022,1118,1119],{"class":1093},";\n",[1022,1121,1123,1126,1130,1133,1135,1139,1142,1145,1148,1151],{"class":1078,"line":1122},4,[1022,1124,1125],{"class":1111},"int",[1022,1127,1129],{"class":1128},"s2Zo4"," main",[1022,1131,1132],{"class":1093},"(",[1022,1134,1125],{"class":1111},[1022,1136,1138],{"class":1137},"sHdIc"," argc",[1022,1140,1141],{"class":1093},",",[1022,1143,1144],{"class":1111}," char**",[1022,1146,1147],{"class":1137}," argv",[1022,1149,1150],{"class":1093},")",[1022,1152,1153],{"class":1093}," {\n",[1022,1155,1157,1160,1163,1167,1170,1173,1175],{"class":1078,"line":1156},5,[1022,1158,1159],{"class":1089},"    if",[1022,1161,1162],{"class":1093}," (",[1022,1164,1166],{"class":1165},"sTEyZ","argc ",[1022,1168,1169],{"class":1093},"==",[1022,1171,1172],{"class":1107}," 1",[1022,1174,1150],{"class":1093},[1022,1176,1153],{"class":1093},[1022,1178,1180,1184,1187,1190],{"class":1078,"line":1179},6,[1022,1181,1183],{"class":1182},"swJcz","        cout ",[1022,1185,1186],{"class":1093},"\u003C\u003C",[1022,1188,1189],{"class":1182}," endl",[1022,1191,1119],{"class":1093},[1022,1193,1195,1198,1201],{"class":1078,"line":1194},7,[1022,1196,1197],{"class":1093},"    }",[1022,1199,1200],{"class":1089}," else",[1022,1202,1153],{"class":1093},[1022,1204,1206,1208,1210,1212,1215,1218,1221,1224,1226],{"class":1078,"line":1205},8,[1022,1207,1183],{"class":1182},[1022,1209,1186],{"class":1093},[1022,1211,1147],{"class":1165},[1022,1213,1214],{"class":1093},"[",[1022,1216,1217],{"class":1107},"1",[1022,1219,1220],{"class":1093},"]",[1022,1222,1223],{"class":1093}," \u003C\u003C",[1022,1225,1189],{"class":1182},[1022,1227,1119],{"class":1093},[1022,1229,1231],{"class":1078,"line":1230},9,[1022,1232,1233],{"class":1093},"    }\n",[1022,1235,1237],{"class":1078,"line":1236},10,[1022,1238,1239],{"class":1093},"}\n",[923,1241,1242,1243,1246,1247,1250],{},"喏，就这么简单。但是，它其中有特别之处：main 函数的声明和我们之前见到的不一样。它接受两个参数 ",[937,1244,1245],{},"argc"," 和 ",[937,1248,1249],{},"argv","。这种形式的 main 函数表明程序需要用到命令的“参数”。",[923,1252,1253,1254,1257,1258,1261,1262,1058,1264,1266],{},"壳层在启动程序时，会特别地分配一个块内存空间，用来存放被空格分隔的命令。此外，还有一个 ",[937,1255,1256],{},"arg"," 数组，其元素都是 ",[937,1259,1260],{},"char*"," 类型的，分别指向这些被空格分隔的命令片段。比如当以 ",[937,1263,956],{},[937,1265,1030],{}," 程序时——",[923,1268,1269],{},[929,1270],{"alt":931,"src":1271},"https:\u002F\u002Fz3.ax1x.com\u002F2021\u002F08\u002F30\u002Fht5p28.png",[923,1273,1274,1275,1277,1278,1280,1281,1283,1284,1246,1286,1288,1289,1246,1291,1293,1294,1296],{},"图中也可看到，",[937,1276,1256],{}," 数组的长度称作 ",[937,1279,1245],{},"，指向数组首元素的指针称作 ",[937,1282,1249],{},"。",[937,1285,1245],{},[937,1287,1249],{}," 同时也是 main 函数可选的两个参数。最终借助 ",[937,1290,1245],{},[937,1292,1249],{},"，程序得到了命令行的“参数”。下面的 ",[937,1295,1030],{}," 源码详细地解释了其工作原理：",[1069,1298,1300],{"className":1071,"code":1299,"language":1073,"meta":931,"style":931},"\u002F\u002F echo.cpp 超级简化版 echo 源码\n#include \u003Ciostream>\nusing namespace std;\nint main(int argc, char** argv) {\n    if (argc == 1) {\n        \u002F\u002F argc 等于 1，也就是说命令被空格分隔后只有一个元素\n        \u002F\u002F 也就是说命令只能长成 \"echo\" 的形式，不带任何额外的参数\n        \u002F\u002F 此时只需输出一个换行即可\n        cout \u003C\u003C endl;\n    } else {\n        \u002F\u002F 否则的话，命令带有额外的参数。比如：\n        \u002F\u002F \"echo Hello\"\n        \u002F\u002F 由于 argv 是 arg 数组首元素，可以得到\n        \u002F\u002F argv[0] 指向 \"echo\"，argv[1] 指向 \"Hello\"\n        \u002F\u002F echo 程序需要输出参数，所以这里 cout argv[1]\n        cout \u003C\u003C argv[1] \u003C\u003C endl;\n    }\n}\n",[937,1301,1302,1306,1316,1326,1348,1364,1369,1374,1379,1389,1397,1403,1409,1415,1421,1427,1448,1453],{"__ignoreMap":931},[1022,1303,1304],{"class":1078,"line":1079},[1022,1305,1083],{"class":1082},[1022,1307,1308,1310,1312,1314],{"class":1078,"line":1086},[1022,1309,1090],{"class":1089},[1022,1311,1094],{"class":1093},[1022,1313,1098],{"class":1097},[1022,1315,1101],{"class":1093},[1022,1317,1318,1320,1322,1324],{"class":1078,"line":1104},[1022,1319,1108],{"class":1107},[1022,1321,1112],{"class":1111},[1022,1323,1116],{"class":1115},[1022,1325,1119],{"class":1093},[1022,1327,1328,1330,1332,1334,1336,1338,1340,1342,1344,1346],{"class":1078,"line":1122},[1022,1329,1125],{"class":1111},[1022,1331,1129],{"class":1128},[1022,1333,1132],{"class":1093},[1022,1335,1125],{"class":1111},[1022,1337,1138],{"class":1137},[1022,1339,1141],{"class":1093},[1022,1341,1144],{"class":1111},[1022,1343,1147],{"class":1137},[1022,1345,1150],{"class":1093},[1022,1347,1153],{"class":1093},[1022,1349,1350,1352,1354,1356,1358,1360,1362],{"class":1078,"line":1156},[1022,1351,1159],{"class":1089},[1022,1353,1162],{"class":1093},[1022,1355,1166],{"class":1165},[1022,1357,1169],{"class":1093},[1022,1359,1172],{"class":1107},[1022,1361,1150],{"class":1093},[1022,1363,1153],{"class":1093},[1022,1365,1366],{"class":1078,"line":1179},[1022,1367,1368],{"class":1082},"        \u002F\u002F argc 等于 1，也就是说命令被空格分隔后只有一个元素\n",[1022,1370,1371],{"class":1078,"line":1194},[1022,1372,1373],{"class":1082},"        \u002F\u002F 也就是说命令只能长成 \"echo\" 的形式，不带任何额外的参数\n",[1022,1375,1376],{"class":1078,"line":1205},[1022,1377,1378],{"class":1082},"        \u002F\u002F 此时只需输出一个换行即可\n",[1022,1380,1381,1383,1385,1387],{"class":1078,"line":1230},[1022,1382,1183],{"class":1182},[1022,1384,1186],{"class":1093},[1022,1386,1189],{"class":1182},[1022,1388,1119],{"class":1093},[1022,1390,1391,1393,1395],{"class":1078,"line":1236},[1022,1392,1197],{"class":1093},[1022,1394,1200],{"class":1089},[1022,1396,1153],{"class":1093},[1022,1398,1400],{"class":1078,"line":1399},11,[1022,1401,1402],{"class":1082},"        \u002F\u002F 否则的话，命令带有额外的参数。比如：\n",[1022,1404,1406],{"class":1078,"line":1405},12,[1022,1407,1408],{"class":1082},"        \u002F\u002F \"echo Hello\"\n",[1022,1410,1412],{"class":1078,"line":1411},13,[1022,1413,1414],{"class":1082},"        \u002F\u002F 由于 argv 是 arg 数组首元素，可以得到\n",[1022,1416,1418],{"class":1078,"line":1417},14,[1022,1419,1420],{"class":1082},"        \u002F\u002F argv[0] 指向 \"echo\"，argv[1] 指向 \"Hello\"\n",[1022,1422,1424],{"class":1078,"line":1423},15,[1022,1425,1426],{"class":1082},"        \u002F\u002F echo 程序需要输出参数，所以这里 cout argv[1]\n",[1022,1428,1430,1432,1434,1436,1438,1440,1442,1444,1446],{"class":1078,"line":1429},16,[1022,1431,1183],{"class":1182},[1022,1433,1186],{"class":1093},[1022,1435,1147],{"class":1165},[1022,1437,1214],{"class":1093},[1022,1439,1217],{"class":1107},[1022,1441,1220],{"class":1093},[1022,1443,1223],{"class":1093},[1022,1445,1189],{"class":1182},[1022,1447,1119],{"class":1093},[1022,1449,1451],{"class":1078,"line":1450},17,[1022,1452,1233],{"class":1093},[1022,1454,1456],{"class":1078,"line":1455},18,[1022,1457,1239],{"class":1093},[918,1459,1461],{"id":1460},"工作路径和-path","工作路径和 PATH",[923,1463,1464],{},"壳层需要在文件系统的一个特定的路径中工作。这个路径称为工作路径（Working Directory）。工作路径一般作为壳层的输入提示符（Input prompt）来呈现：",[923,1466,947],{},[923,1468,1469,1470,1473],{},"上图中框起的部分就是当前壳层所处的工作路径。壳层的工作路径一定程度上决定了壳层怎样通过命令中的“程序名”来找到它该启动的程序。首先最基本的，你可以通过 ",[937,1471,1472],{},"@\"cd\" 路径名@"," 来更换壳层的工作路径：",[923,1475,947],{},[1039,1477,1478],{},[923,1479,1480,1482,1483,1486],{},[937,1481,1472],{}," 并不是常规的命令格式。因为 ",[937,1484,1485],{},"cd"," 不是一个程序名，而是壳层的内置命令：它并不启动任何程序，而是告诉壳层更换其工作路径。",[1039,1488,1489],{},[923,1490,1491,1492,1494,1495,1498,1499,1502,1503,1506,1507,1246,1510,1513],{},"Windows 下的 ",[937,1493,973],{}," 壳层出于历史原因，无法更换工作路径到其它磁盘。你需要输入 ",[937,1496,1497],{},"@盘符\":\"@"," 命令来切换到其它磁盘。比如，将工作路径从 ",[937,1500,1501],{},"C:\\Windows\\system32"," 切换到 ",[937,1504,1505],{},"D:\\MyFiles","，需要执行 ",[937,1508,1509],{},"D:",[937,1511,1512],{},"cd D:\\MyFiles"," 两条命令。",[923,1515,1516,1517,1519,1520,1246,1523,1526],{},"可以从输入提示符中看到，执行 ",[937,1518,1485],{}," 命令后壳层的工作路径发生了改变。此外，有两个特殊的记号 ",[937,1521,1522],{},".",[937,1524,1525],{},".."," 需要记忆：",[1528,1529,1530,1536],"ul",{},[1531,1532,1533,1535],"li",{},[937,1534,1522],{}," 总是代表当前路径；",[1531,1537,1538,1540],{},[937,1539,1525],{}," 代表上层路径（对于根目录则是自身）。",[923,1542,1543,1544,1246,1547,1550],{},"你可以试一下 ",[937,1545,1546],{},"cd .",[937,1548,1549],{},"cd .."," 的效果，想一想为什么。",[923,1552,947],{},[923,1554,1555,1556,1558,1559,1561,1562,1565,1566,1569,1570,1573,1574,1576],{},"这个 ",[937,1557,1522],{}," 的作用不可小觑。",[937,1560,1522],{}," 提供了方便地运行工作路径下程序的方法。比如你的壳层目前在 ",[937,1563,1564],{},"\u002Fhome\u002Fuser\u002F"," 路径下工作，而就在刚刚你用 ",[937,1567,1568],{},"echo.cpp"," 编译出了 ",[937,1571,1572],{},"\u002Fhome\u002Fuser\u002Fecho"," 可执行文件。则你可以直接这样执行这个 ",[937,1575,1572],{}," 程序：",[923,1578,947],{},[923,1580,1581,1582,1585,1586,1588,1589,1591,1592,1595,1596,1599],{},"显然，",[937,1583,1584],{},".\u002Fecho"," 就代表了 ",[937,1587,1572],{},"；因为 ",[937,1590,1522],{}," 就是工作路径 ",[937,1593,1594],{},"\u002Fhome\u002Fuser"," 嘛。当然如果不嫌麻烦的话，你也可以执行 ",[937,1597,1598],{},"\u002Fhome\u002Fuser\u002Fecho Hello"," 这样的命令。",[923,1601,1602,1603,1606,1607,1609],{},"操作系统提供一些常用的程序。GNU\u002FLinux 中，它们大多位于 ",[937,1604,1605],{},"\u002Fbin"," 路径下，而 Windows 中，它们大多位于 ",[937,1608,1501],{}," 下。这些程序很常用，以至于我不希望在调用它们的时候总是带着长长的路径名：",[923,1611,947],{},[923,1613,1614],{},"因此操作系统为这些路径提供了快捷方式：PATH 环境变量。你可以将 PATH 环境变量想象为一个字符串数组，其中是大量常用程序所在的路径。比如",[1528,1616,1617,1641],{},[1531,1618,1619,1620],{},"Windows 的默认 PATH 环境变量一般是：\n",[1528,1621,1622,1626,1631,1636],{},[1531,1623,1624],{},[937,1625,1501],{},[1531,1627,1628],{},[937,1629,1630],{},"C:\\Windows",[1531,1632,1633],{},[937,1634,1635],{},"C:\\Windows\\System32\\Wbem",[1531,1637,1638],{},[937,1639,1640],{},"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\",[1531,1642,1643,1644],{},"GNU\u002FLinux 的默认 PATH 环境变量一般是：\n",[1528,1645,1646,1651,1656,1661,1666,1671,1675],{},[1531,1647,1648],{},[937,1649,1650],{},"\u002Fusr\u002Flocal\u002Fsbin",[1531,1652,1653],{},[937,1654,1655],{},"\u002Fusr\u002Flocal\u002Fbin",[1531,1657,1658],{},[937,1659,1660],{},"\u002Fusr\u002Fsbin",[1531,1662,1663],{},[937,1664,1665],{},"\u002Fusr\u002Fbin",[1531,1667,1668],{},[937,1669,1670],{},"\u002Fsbin",[1531,1672,1673],{},[937,1674,1605],{},[1531,1676,1677],{},[937,1678,1679],{},"\u002Fusr\u002Fgames",[923,1681,1682,1683,1686,1687,1690,1691,1694,1695,1698],{},"PATH 环境变量中的程序在执行时只需给出程序名，而不用给出其路径。所以，你在 Windows 下执行 ",[937,1684,1685],{},"C:\\Windows\\system32\\ipconfig.exe"," 程序并不需要输入这样长长一串路径，只需输入 ",[937,1688,1689],{},"ipconfig.exe"," 就够了；在 GNU\u002FLinux 下执行 ",[937,1692,1693],{},"\u002Fusr\u002Fbin\u002Fdate"," 程序也只需输入 ",[937,1696,1697],{},"date"," 就够了。",[923,1700,1701],{},"图？",[923,1703,1704,1705,1708,1709,1712],{},"我们在写 C++ 程序之前，首先要做的就是配置 C++ 编程环境。而配置编程环境中常需要做的一件事情就是把编译器添加到 PATH 环境变量中。编译器可能会安装到任何地方，但如果想要快速地在壳层中启动编译器，则需要将它的位置放在 PATH 环境变量中。以 GNU\u002FLinux 举例，其常用的 C++ 编译器经常安装在 ",[937,1706,1707],{},"\u002Fusr\u002Fbin\u002Fg++"," 中，但日常使用时只需输入 ",[937,1710,1711],{},"g++"," 命令就够了。",[918,1714,1716],{"id":1715},"在-cli-中使用编译器","在 CLI 中使用编译器",[923,1718,1719,1720,1722,1723,1725],{},"假设我们的 C++ 编译器名字叫 ",[937,1721,1711],{},"。事实上，它是 GNU\u002FLinux 操作系统的最常用编译器，也是 Windows 下广泛使用的 MinGW 编译环境所提供的编译器。在 macOS 上，",[937,1724,1711],{}," 也一般会设置为其常用编译器——AppleClang 的别名。",[1039,1727,1728],{},[923,1729,1730,1731,1734],{},"常见的唯一例外是 Microsoft Visual C++（MSVC，即 Visual Studio），其编译器名叫 ",[937,1732,1733],{},"cl.exe","，且安装 Visual Studio 时也一般不将它添加到 PATH 环境变量中。",[923,1736,1737],{},"几乎所有的编译器都是以命令行界面来操作的。（换而言之 IDE 只是用漂亮的图形元素包装了这些命令行界面。）对于 g++ 来说，最常见的命令形式长成这样：",[1016,1739,1740],{},[923,1741,1742],{},"\"g++\" 源文件路径 \"-o\" 编译得到的可执行文件路径",[923,1744,1745,1746,1748,1749,1752],{},"为了演示，仍然假设我们的壳层于 ",[937,1747,1594],{}," 路径下工作。这里存放了一个名为 ",[937,1750,1751],{},"helloworld.cpp"," 的文件：",[1069,1754,1756],{"className":1071,"code":1755,"language":1073,"meta":931,"style":931},"\u002F\u002F \u002Fhome\u002Fuser\u002Fhelloworld.cpp\n#include \u003Ciostream>\nint main() {\n    std::cout \u003C\u003C \"Hello, world!\" \u003C\u003C std::endl;\n}\n",[937,1757,1758,1763,1773,1784,1817],{"__ignoreMap":931},[1022,1759,1760],{"class":1078,"line":1079},[1022,1761,1762],{"class":1082},"\u002F\u002F \u002Fhome\u002Fuser\u002Fhelloworld.cpp\n",[1022,1764,1765,1767,1769,1771],{"class":1078,"line":1086},[1022,1766,1090],{"class":1089},[1022,1768,1094],{"class":1093},[1022,1770,1098],{"class":1097},[1022,1772,1101],{"class":1093},[1022,1774,1775,1777,1779,1782],{"class":1078,"line":1104},[1022,1776,1125],{"class":1111},[1022,1778,1129],{"class":1128},[1022,1780,1781],{"class":1093},"()",[1022,1783,1153],{"class":1093},[1022,1785,1786,1789,1792,1795,1797,1800,1803,1806,1808,1810,1812,1815],{"class":1078,"line":1122},[1022,1787,1788],{"class":1115},"    std",[1022,1790,1791],{"class":1093},"::",[1022,1793,1794],{"class":1165},"cout ",[1022,1796,1186],{"class":1093},[1022,1798,1799],{"class":1093}," \"",[1022,1801,1802],{"class":1097},"Hello, world!",[1022,1804,1805],{"class":1093},"\"",[1022,1807,1223],{"class":1093},[1022,1809,1116],{"class":1115},[1022,1811,1791],{"class":1093},[1022,1813,1814],{"class":1165},"endl",[1022,1816,1119],{"class":1093},[1022,1818,1819],{"class":1078,"line":1156},[1022,1820,1239],{"class":1093},[923,1822,1823],{},"然后尝试用 g++ 编译器编译它。在壳层中执行如下命令：",[1825,1826,1827],"io-block",{},[923,1828,1829],{},"¶g++ .\u002Fhelloworld.cpp -o .\u002Fhelloworld.exe↵",[923,1831,1832,1833,1835,1836,1839,1840,1842],{},"如果没有语法错误的话，g++ 编译器将什么都不会输出，直接默默地成功执行了。你可以检查一下，",[937,1834,1594],{}," 路径下应当多了一个名为 ",[937,1837,1838],{},"helloworld.exe"," 的文件，这就是 g++ 编译的结果。接下来，尝试通过刚才学到的方法来运行这个 ",[937,1841,1838],{}," 程序。在壳层中执行：",[1825,1844,1845],{},[923,1846,1847],{},"¶.\u002Fhelloworld.exe↵",[923,1849,1850,1851,1853],{},"应当能够看到输出 ",[937,1852,1802],{},"。这样，我们成功地做到了在 CLI 下编译并运行 C++ 程序。",[1039,1855,1856],{},[923,1857,1858],{},"“一个程序成功执行了它该做的事情时，不输出任何东西；仅当程序出现错误时才会输出错误提示。”这种行为有时被称为 UNIX 哲学：因为曾经及其著名的元祖级别的操作系统 UNIX 的内置程序采用了这种风格的行为。",[918,1860,1861],{"id":1861},"多文件编译",[923,1863,1864,1865,1868,1869,1871,1872,1875,1876,1246,1879,1882],{},"这里，我将使用在",[1866,1867,1861],"a",{"href":663},"中的三文件例子。现在，",[937,1870,1594],{}," 路径下存在 ",[937,1873,1874],{},"main.cpp"," ",[937,1877,1878],{},"hello.h",[937,1880,1881],{},"hello.cpp"," 三个文件。",[923,1884,1885,1886,1246,1888,1890],{},"这里有两个编译单元 ",[937,1887,1874],{},[937,1889,1881],{},"。将它们一起编译的方法非常简单，只需执行如下命令即可：",[1825,1892,1893],{},[923,1894,1895],{},"¶g++ .\u002Fmain.cpp .\u002Fhello.cpp -o .\u002Fmain.exe↵",[923,1897,1898,1899,1902,1903,1246,1906,1909,1910,1914,1915,1917,1918,1921],{},"在这条命令中，结尾的 ",[937,1900,1901],{},"-o .\u002Fmain.exe"," 仍然用于指示可执行文件名；但不同于之前，这次使用 ",[937,1904,1905],{},".\u002Fmain.cpp",[937,1907,1908],{},".\u002Fhello.cpp"," 两个参数来告诉编译器将哪些源文件作为翻译单元。当指定多个翻译单元时，编译器会分别",[1911,1912,1913],"em",{},"编译","这些翻译单元，并在",[1911,1916,1913],{},"完成后自动调用链接器来链接它们，最终将链接的结果转换为可执行文件保存到 ",[937,1919,1920],{},".\u002Fmain.exe"," 中。",[923,1923,1924],{},"在本文靠后的部分中，我将继续阐述一些有关多文件编译的细节问题。不过在此之前，容我先插入有关命令行选项的介绍。",[918,1926,1927],{"id":1927},"命令行选项",[923,1929,1930,1931,1934,1935,1937,1938,1940],{},"大量 UNIX 风格的软件使用了名为 ",[937,1932,1933],{},"getopt"," 的库来处理命令行参数。",[937,1936,1711],{}," 编译器也不例外。",[937,1939,1933],{}," 库所能处理的命令行参数有其特别的风格，而这种风格及其广泛地影响了大量的程序，因此值得一提。",[923,1942,1943,1944,1946,1947,1950],{},"首先，",[937,1945,1933],{}," 将命令行参数分为“选项”和“非选项”两种类别。选项是指一系列由 ",[937,1948,1949],{},"-"," 减号开头的若干个参数。比如：",[1825,1952,1953],{},[923,1954,1955],{},"¶g++ -V↵",[1825,1957,1958],{},[923,1959,1960],{},"¶g++ --version↵",[923,1962,1963,1964,1246,1967,1970,1971,1973,1974,1977,1978,1981,1982,1984,1985,1283],{},"中，",[937,1965,1966],{},"-V",[937,1968,1969],{},"--version"," 这两个参数就是选项。这种简单的减号开头的选项称为“开关”或“布尔开关”。它仿佛给程序传入了一个布尔类型变量——好比说，如果参数中带有 ",[937,1972,1969],{},"，程序中的某个布尔变量 ",[937,1975,1976],{},"showVersion"," 就设置为 ",[937,1979,1980],{},"true","；如果不带 ",[937,1983,1969],{},"，则设置为 ",[937,1986,1987],{},"false",[923,1989,1990,1991,1993,1994,1996],{},"使用 ",[937,1992,1933],{}," 库的程序会规定一些可用的选项。如果你使用了这些规定之外的选项作为参数，那么你会得到一个 ",[937,1995,1933],{}," 错误。",[1825,1998,1999],{},[923,2000,2001],{},"¶g++ --abcde↵\ng++.exe: error: unrecognized command-line option '-abcde'",[923,2003,2004,2005,2008,2009,2011,2012,2014],{},"这个例子中，我是用了未定义的选项 ",[937,2006,2007],{},"--abcde","。（因为这个参数是减号开头的，所以它被识别为选项。）然而，",[937,2010,1711],{}," 并不认识 ",[937,2013,2007],{}," 这个选项，所以它给出“未识别的命令行选项”错误。",[923,2016,2017,2018,1246,2021,2023,2024,2026,2027,2029],{},"几乎所有的程序都会规定 ",[937,2019,2020],{},"--help",[937,2022,1969],{}," 两个布尔开关。当启用 ",[937,2025,2020],{}," 开关时，程序一般会输出帮助信息——关于如何使用此程序的帮助；当启用 ",[937,2028,1969],{}," 开关时，程序一般会输出版本信息。",[1825,2031,2032],{},[923,2033,2034,2035,2038,2039,2042],{},"¶g++ --help↵\nUsage: g++.exe ",[1022,2036,2037],{},"options"," file...\nOptions:\n-pass-exit-codes         Exit with highest error code from a phase.\n--help                   Display this information.\n",[1022,2040,2041],{},"..."," 非常长的 g++ 帮助信息",[923,2044,2045,2046,2048],{},"布尔开关如同给程序传入了一个布尔变量，但如果要传入其它类型的变量就比较费力气了。所以，",[937,2047,1933],{}," 引入“带值的”选项的概念。比如：",[1825,2050,2051],{},[923,2052,2053],{},"¶g++ -x=c++↵\n¶g++ -xc++↵\n¶g++ -x c++↵",[923,2055,2056,2057,2060,2061,2064,2065,1283,2068,2070,2071,2074,2075,2077,2078,1875,2080,2083,2084,1875,2086,2089,2090,2092,2093,2095,2096,2099],{},"上面这三行的意思都是，",[937,2058,2059],{},"-x"," 选项带有一个额外的字符串值 ",[937,2062,2063],{},"c++","。换而言之，这里如同将程序中的某个字符串类型变量设置为 ",[937,2066,2067],{},"\"c++\"",[937,2069,1933],{}," 支持三种类型的“带值的”选项，即用 ",[937,2072,2073],{},"="," 等号分隔名字和值、用 ",[937,2076,1875],{}," 空格分隔名字和值，以及不加任何分隔符。显然，最后一种要求选项只能是单个字母形式的（如 ",[937,2079,2059],{},[937,2081,2082],{},"-L","）而不能是多个字母（如 ",[937,2085,2020],{},[937,2087,2088],{},"-specs","）。在 ",[937,2091,1711],{}," 中，有些选项只支持 ",[937,2094,2073],{}," 分隔的值（比如 ",[937,2097,2098],{},"-std","），有些选项只支持后两者；具体情况需要查看帮助文档。",[923,2101,2102,2103,2105],{},"除了布尔开关、带值的选项，剩余的所有参数都是“非选项”参数。在 ",[937,2104,1711],{}," 中，所有非选项参数都视为源文件——即翻译单元。",[1825,2107,2108],{},[923,2109,2110],{},"¶g++ abcd↵",[923,2112,2113,2114,2117,2118,2120,2121,2123],{},"这里，",[937,2115,2116],{},"abcd"," 因为不是减号开头的，所以不会被识别为布尔开关或者选项。所有它是非选项参数。所以 ",[937,2119,1711],{}," 会尝试在壳层的当前工作路径中寻找名为 ",[937,2122,2116],{}," 的源文件，并将其作为翻译单元进行编译。如果找不到这个文件，则给出错误。",[923,2125,2126],{},"最后回过头来看一看最初的这条命令：",[1825,2128,2129],{},[923,2130,1895],{},[923,2132,2113,2133,2135,2136,1246,2138,2140,2141,2143,2144,2146,2147,2150,2151,2153,2154,2156],{},[937,2134,1901],{}," 就是带值的选项，而 ",[937,2137,1905],{},[937,2139,1908],{}," 则是非选项参数。因此，",[937,2142,1711],{}," 将后两者认定为翻译单元。在 ",[937,2145,1711],{}," 中，",[937,2148,2149],{},"-o"," 选项可选地带有一个值，指定了编译的结果存放在哪里。所以 ",[937,2152,1901],{}," 就是将可执行文件存放在 ",[937,2155,1920],{}," 这个文件中。",[923,2158,2159,2160,2162,2163,2165],{},"常用的 ",[937,2161,1711],{}," 选项除了 ",[937,2164,2149],{}," 外，还有：",[2167,2168,2169,2182],"table",{},[2170,2171,2172],"thead",{},[2173,2174,2175,2179],"tr",{},[2176,2177,2178],"th",{},"选项名",[2176,2180,2181],{},"说明",[2183,2184,2185,2204,2224,2234],"tbody",{},[2173,2186,2187,2194],{},[2188,2189,2190,2193],"td",{},[937,2191,2192],{},"-std="," 标准",[2188,2195,2196,2197,1875,2200,2203],{},"指定语言标准，如 ",[937,2198,2199],{},"-std=c++20",[937,2201,2202],{},"std=c++98"," 等",[2173,2205,2206,2212],{},[2188,2207,2208,2211],{},[937,2209,2210],{},"-O"," 等级",[2188,2213,2214,2215,1875,2218,1875,2221,2203],{},"指定优化等级，如 ",[937,2216,2217],{},"-O1",[937,2219,2220],{},"-O2",[937,2222,2223],{},"-Ofast",[2173,2225,2226,2231],{},[2188,2227,2228],{},[937,2229,2230],{},"-Wall",[2188,2232,2233],{},"给出比一般情况下更多的警告",[2173,2235,2236,2241],{},[2188,2237,2238],{},[937,2239,2240],{},"-Werror",[2188,2242,2243],{},"视警告为错误，即出现警告则编译失败",[918,2245,2247,2249],{"id":2246},"g-中的翻译阶段",[937,2248,1711],{}," 中的翻译阶段",[923,2251,2252],{},"我们已经知道的是 C++ 翻译分为预处理、编译和链接三个大阶段。而编译则可更细划分出“汇编”一个阶段。也就是说，完整的翻译阶段分为如下几步：",[923,2254,947],{},[923,2256,2257,2258,2260,2261,2264,2265,2268,2269,2271],{},"其实，",[937,2259,1711],{}," 可以完成图中从任意一个阶段到另外一个阶段的流程。平时，我们总是直接从 ",[937,2262,2263],{},".cpp"," 源文件一下子到 ",[937,2266,2267],{},".exe"," 可执行文件，但通过调整 ",[937,2270,1711],{}," 的命令行选项，可以指定其只完成其中部分阶段。",[923,2273,1943,2274,2276],{},[937,2275,1711],{}," 通过文件后缀名来判断其流程的起点。",[2167,2278,2279,2291],{},[2170,2280,2281],{},[2173,2282,2283,2286],{},[2176,2284,2285],{},"后缀名",[2176,2287,2288,2290],{},[937,2289,1711],{}," 的行为",[2183,2292,2293,2311,2321,2334],{},[2173,2294,2295,2308],{},[2188,2296,2297,1875,2299,1875,2302,1875,2305,2203],{},[937,2298,2263],{},[937,2300,2301],{},".c++",[937,2303,2304],{},".cc",[937,2306,2307],{},".cxx",[2188,2309,2310],{},"视为源文件，将预处理作为第一步",[2173,2312,2313,2318],{},[2188,2314,2315],{},[937,2316,2317],{},".ii",[2188,2319,2320],{},"视为预处理后的源文件，将编译作为第一步",[2173,2322,2323,2331],{},[2188,2324,2325,1875,2328,2203],{},[937,2326,2327],{},".s",[937,2329,2330],{},".S",[2188,2332,2333],{},"视为汇编文件，将汇编作为第一步",[2173,2335,2336,2346],{},[2188,2337,2338,2339,1875,2342,2345],{},"其它（一般为 ",[937,2340,2341],{},".o",[937,2343,2344],{},".obj","）",[2188,2347,2348],{},"视为对象文件，将链接作为第一步",[923,2350,2351],{},"比如",[1825,2353,2354],{},[923,2355,2356],{},"¶g++ .\u002Fhello.cpp↵",[923,2358,1963,2359,2361,2362,2364],{},[937,2360,1711],{}," 将 ",[937,2363,1908],{}," 视为源文件，从而执行预处理、编译、汇编、链接这四个流程，得到可执行文件。又比如",[1825,2366,2367],{},[923,2368,2369],{},"¶g++ .\u002Fhello.s↵",[923,2371,1963,2372,2361,2374,2377],{},[937,2373,1711],{},[937,2375,2376],{},".\u002Fhello.s"," 视为汇编文件，故只会执行汇编、链接两个流程，得到可执行文件。",[923,2379,2380,2381,2383],{},"其次，",[937,2382,1711],{}," 通过若干个选项来控制器流程的终点。",[2167,2385,2386,2397],{},[2170,2387,2388],{},[2173,2389,2390,2393],{},[2176,2391,2392],{},"选项",[2176,2394,2395,2290],{},[937,2396,1711],{},[2183,2398,2399,2409,2419,2429],{},[2173,2400,2401,2406],{},[2188,2402,2403],{},[937,2404,2405],{},"-E",[2188,2407,2408],{},"将预处理作为最后一步，得到预处理后的源文件",[2173,2410,2411,2416],{},[2188,2412,2413],{},[937,2414,2415],{},"-S",[2188,2417,2418],{},"将编译作为最后一步，得到汇编文件",[2173,2420,2421,2426],{},[2188,2422,2423],{},[937,2424,2425],{},"-c",[2188,2427,2428],{},"将汇编作为最后一步，得到对象文件",[2173,2430,2431,2434],{},[2188,2432,2433],{},"不含以上选项",[2188,2435,2436],{},"将链接作为最后一步，得到可执行文件",[923,2438,2351],{},[1825,2440,2441],{},[923,2442,2356],{},[923,2444,2445,2446,1875,2448,2450,2451,2453,2454,2456],{},"中，由于没有指定 ",[937,2447,2405],{},[937,2449,2415],{}," 或 ",[937,2452,2425],{}," 选项，所以 ",[937,2455,1711],{}," 会走到最后一步生成可执行文件。又比如",[1825,2458,2459],{},[923,2460,2461],{},"¶g++ .\u002Fhello.cpp -c↵",[923,2463,2464,2465,2453,2467,2469,2470,2473],{},"中，由于指定了 ",[937,2466,2425],{},[937,2468,1711],{}," 只会执行预处理、编译、汇编三个流程，随后就终止了。最终只会生成名字类似 ",[937,2471,2472],{},"hello.o"," 的对象文件，而不是可执行文件。",[923,2475,2476,2477,2479],{},"此时，",[937,2478,2149],{}," 不仅指定可执行文件的名字，还执行每次流程结束后得到结果的名字。比如",[1825,2481,2482],{},[923,2483,2484],{},"¶g++ .\u002Fhello.cpp -c -o abc.o↵",[923,2486,2487,2488,2491,2492,2494,2495,2497,2498,2500,2501,2503,2504,2500,2506,2508,2509,2450,2512,1283],{},"就会生成名为 ",[937,2489,2490],{},"abc.o"," 的对象文件。当不指定 ",[937,2493,2149],{}," 时，",[937,2496,2405],{}," 会将预处理后的文件输出到屏幕上；",[937,2499,2415],{}," 会以 ",[937,2502,2327],{}," 后缀名保存结果，",[937,2505,2425],{},[937,2507,2341],{}," 后缀名保存结果；可执行文件名则为 ",[937,2510,2511],{},"a.out",[937,2513,2514],{},"a.exe",[923,2516,2517,2518,2520,2521,2524],{},"如果你想详细查看每一阶段 ",[937,2519,1711],{}," 都做了什么，你可以将这四个阶段分开执行。下面的命令分别执行了其中单个阶段，并在最后运行这个可执行文件。（注：在大多数壳层程序中，",[937,2522,2523],{},"#"," 代表单行注释，其后内容仅用于注解，不会被壳层处理。）",[1825,2526,2527],{},[923,2528,2529],{},"¶g++ .\u002Fhello.cpp -E >  .\u002Fhello.ii↵   # 预处理\n¶g++ .\u002Fhello.ii  -S -o .\u002Fhello.s↵    # 编译\n¶g++ .\u002Fhello.s   -c -o .\u002Fhello.o↵    # 汇编\n¶g++ .\u002Fhello.o      -o .\u002Fhello.exe↵  # 链接\n¶.\u002Fhello.exe↵                        # 运行",[1039,2531,2532,2551],{},[923,2533,2534,2536,2537,2539,2540,2543,2544,2547,2548,1921],{},[937,2535,2405],{}," 并不通过 ",[937,2538,2149],{}," 选项来控制输出位置，它直接将预处理结果输出到屏幕（",[937,2541,2542],{},"stdout","）上。所以这里使用了壳层的重定向运算符 ",[937,2545,2546],{},">"," 将其输出保存到我们想要的位置 ",[937,2549,2550],{},".\u002Fhello.ii",[923,2552,2553,2557,2558,2561],{},[2554,2555,2556],"strong",{},"注意","：如果你在 Windows 下使用 PowerShell 来执行上述命令，你可能需要改变重定向的默认编码，比如提前执行 ",[937,2559,2560],{},"$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'"," 命令。",[918,2563,2565],{"id":2564},"gnu-make","GNU Make",[923,2567,2568,2569,1875,2572,1875,2575,2577,2578,1875,2581,1875,2584,2587,2588,2591,2592,2594,2595,2597,2598,1246,2600,2602],{},"当初引入多文件编译的情景是这样的： ",[937,2570,2571],{},"f.cpp",[937,2573,2574],{},"g.cpp",[937,2576,1874],{}," 分别各自编译出 ",[937,2579,2580],{},"f.o",[937,2582,2583],{},"g.o",[937,2585,2586],{},"main.o","，随后再链接为 ",[937,2589,2590],{},"main.exe","。当 ",[937,2593,2571],{}," 有改动时，只需重新编译 ",[937,2596,2580],{}," 并链接，而不需编译 ",[937,2599,2583],{},[937,2601,2586],{},"。这种做法可以大大减少整个项目的编译时间。",[923,2604,2605,2606,1875,2608,2610,2611,2613,2614,2616],{},"但是，我们改动 ",[937,2607,2571],{},[937,2609,2574],{}," 可能是很随意的事情——我可能不记得“",[937,2612,2571],{}," 改过了，待会需要重新生成 ",[937,2615,2580],{},"”这种事情。如果翻译单元多起来，在一次编译中“哪些需要重新编译？哪些不需要？”就变成了很头疼的问题。因此，这里需要一个称作 GNU Make 的工具来解决它。",[923,2618,2619,2620],{},"GNU Make（简称 Make）是一个经典的构建工具。所谓“构建”（Build），就是在一个项目中安排编译的顺序、时机，最终得到你想要的结果（称为“目标”（Target））。它的原理非常简单，就是一件事情：",[2554,2621,2622],{},"目标如何得到？",[923,2624,2625,2626,1875,2629,1875,2632,2635,2636,2638,2639,2641,2642,1875,2644,1875,2646,2648,2649,2651,2652,2654,2655,1875,2657,1875,2659,1882],{},"仍然是之前 ",[937,2627,2628],{},"f",[937,2630,2631],{},"g",[937,2633,2634],{},"main"," 这个情景。我们的目标是生成 ",[937,2637,2590],{},"。那么想一想如何生成 ",[937,2640,2590],{},"？它应该是由 ",[937,2643,2580],{},[937,2645,2583],{},[937,2647,2586],{}," 三个对象文件链接得到的。而且，这三个文件一旦有一个发生更改，那么 ",[937,2650,2590],{}," 就应当重新编译。换而言之，",[937,2653,2590],{}," 依赖于 ",[937,2656,2580],{},[937,2658,2583],{},[937,2660,2586],{},[923,2662,2663,2664,2667,2668,2670],{},"Make 使用一种称为 Makefile 的文件来指明这些构建方法。Makefile 就是文件名为 ",[937,2665,2666],{},"Makefile"," 的文件，不带后缀名。Makefile 使用这样的语法来表示 ",[937,2669,2590],{}," 如何得到：",[1016,2672,2673],{},[923,2674,2675,2676,2679],{},"目标文件\":\" ",[1022,2677,2678],{},"依赖文件1 依赖文件2 ...","\n生成命令",[923,2681,2682,2683,2686],{},"注意 ",[937,2684,2685],{},"@生成命令@"," 前面的空白是一个 Tab 字符，而不是若干个空格。聪明的编辑器在编辑 Makefile 时会处理好这一点。",[923,2688,2689,2690,2692],{},"带入刚才的 ",[937,2691,2590],{}," 的生成方法，则得到这样的 Makefile 片段：",[1069,2694,2698],{"className":2695,"code":2696,"language":2697,"meta":931,"style":931},"language-makefile shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","main.exe: f.o g.o main.o\n    g++ f.o g.o main.o -o main.exe\n","makefile",[937,2699,2700,2705],{"__ignoreMap":931},[1022,2701,2702],{"class":1078,"line":1079},[1022,2703,2704],{},"main.exe: f.o g.o main.o\n",[1022,2706,2707],{"class":1078,"line":1086},[1022,2708,2709],{},"    g++ f.o g.o main.o -o main.exe\n",[923,2711,2712,2713,2715,2716,1875,2718,1875,2720,2722,2723,2726,2727,2729,2730,2732,2733,2735,2736,2738,2739,2741,2742,2744,2745,2747],{},"这表示，要想生成 ",[937,2714,2590],{},"，需要在有 ",[937,2717,2580],{},[937,2719,2583],{},[937,2721,2586],{}," 三个文件的情形下，执行 ",[937,2724,2725],{},"g++ f.o g.o main.o -o main.exe"," 命令来得到。有了这样的 Makefile，Make 就能知道如何生成 ",[937,2728,2590],{}," 目标。那么继续追问，既然得到 ",[937,2731,2590],{}," 需要 ",[937,2734,2580],{},"，那么 ",[937,2737,2580],{}," 如何得到？显然，它是由 ",[937,2740,1711],{}," 带 ",[937,2743,2425],{}," 参数，从 ",[937,2746,2571],{}," 生成的。于是又有了下面三条 Makefile 片段：",[1069,2749,2751],{"className":2695,"code":2750,"language":2697,"meta":931,"style":931},"f.o: f.cpp\n    g++ f.cpp -c -o f.o\u003Cbr>\ng.o: g.cpp\n    g++ g.cpp -c -o g.o\u003Cbr>\nmain.o: main.cpp\n    g++ main.cpp -c -o main.o\n",[937,2752,2753,2758,2763,2768,2773,2778],{"__ignoreMap":931},[1022,2754,2755],{"class":1078,"line":1079},[1022,2756,2757],{},"f.o: f.cpp\n",[1022,2759,2760],{"class":1078,"line":1086},[1022,2761,2762],{},"    g++ f.cpp -c -o f.o\u003Cbr>\n",[1022,2764,2765],{"class":1078,"line":1104},[1022,2766,2767],{},"g.o: g.cpp\n",[1022,2769,2770],{"class":1078,"line":1122},[1022,2771,2772],{},"    g++ g.cpp -c -o g.o\u003Cbr>\n",[1022,2774,2775],{"class":1078,"line":1156},[1022,2776,2777],{},"main.o: main.cpp\n",[1022,2779,2780],{"class":1078,"line":1179},[1022,2781,2782],{},"    g++ main.cpp -c -o main.o\n",[923,2784,2785,2786,2789],{},"Makefile 中保存了这样四个片段后，就可以开始构建了。在壳层中执行 ",[937,2787,2788],{},"make main.exe"," 命令：",[1825,2791,2792],{},[923,2793,2794],{},"¶make main.exe↵",[1039,2796,2797],{},[923,2798,2799,2800,2803,2804,1283],{},"在 MinGW 中，使用 ",[937,2801,2802],{},"mingw32-make"," 来代替 ",[937,2805,2806],{},"make",[923,2808,2809,2810,2812,2813,2815,2816,2818,2819,1875,2821,1875,2823,2825,2826,2818,2828,2830,2831,2833,2834,2836],{},"此命令会以 ",[937,2811,2590],{}," 为参数启动 Make 程序。首先，Make 程序会读取当前工作路径下的 Makefile 来了解构建规则。然后，它根据命令行参数得知我们想要得到 ",[937,2814,2590],{}," 这个目标。于是 Make 就会根据这些构建规则来生成它。Make 可以通过每个文件的最后改动时间来确定一个目标是否需要重新生成，而不用我们再手动判断。比如若 ",[937,2817,2590],{}," 的最后改动时间晚于 ",[937,2820,2571],{},[937,2822,2574],{},[937,2824,1874],{},"，那么 Make 就不会做任何事——因为它知道所有的源代码都没更新，不需要重新编译。又或者 ",[937,2827,2571],{},[937,2829,2580],{},"，那么 Make 就知道 ",[937,2832,2580],{}," 需要更新，然后推导出 ",[937,2835,2590],{}," 需要更新。类似这样，Make 通过我们在 Makefile 中指定的构建规则来自动地管理编译顺序和时机。",[918,2838,2840],{"id":2839},"cmake","CMake",[923,2842,2843],{},"可以看出，通过 Make 来管理构建方法是一种非常原始的策略。我现在有三个翻译单元，我就需要写至少三个生成规则；翻译单元越多，编写 Makefile 的难度就越大。所以，CMake 工具横空出世。",[923,2845,2846,2847,2850,2851,2853,2854,2856],{},"简单说，CMake 可以通过一个名为 ",[937,2848,2849],{},"CMakeLists.txt"," 的脚本来生成 Makefile。但 ",[937,2852,2849],{}," 的语法比 Makefile 复杂得多，我只能在这里简要介绍。仍然用老例子，它的 ",[937,2855,2849],{}," 长成这样：",[1069,2858,2861],{"className":2859,"code":2860,"language":2839,"meta":931,"style":931},"language-cmake shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","cmake_minimum_required(VERSION 3.18.0)\nproject(HelloWorld)\nadd_executable(main main.cpp f.cpp g.cpp)\n",[937,2862,2863,2868,2873],{"__ignoreMap":931},[1022,2864,2865],{"class":1078,"line":1079},[1022,2866,2867],{},"cmake_minimum_required(VERSION 3.18.0)\n",[1022,2869,2870],{"class":1078,"line":1086},[1022,2871,2872],{},"project(HelloWorld)\n",[1022,2874,2875],{"class":1078,"line":1104},[1022,2876,2877],{},"add_executable(main main.cpp f.cpp g.cpp)\n",[923,2879,2880,2881,2884,2885,2887,2888,1875,2890,1875,2892,2894],{},"第一行规定了最低 CMake 版本，没啥意思。第二行指定了项目名称。第三行是重点： ",[937,2882,2883],{},"add_executable"," 告诉 CMake，我最终要生成一个可执行文件。可执行文件的名字叫 ",[937,2886,2634],{},"，它需要从 ",[937,2889,1874],{},[937,2891,2571],{},[937,2893,2574],{}," 三个文件编译链接得到。",[923,2896,2897,2898,2900],{},"安装 CMake 后，在源代码位置新建一个 build 文件夹，然后把壳层程序 ",[937,2899,1485],{}," 到这个 build 文件夹。接着，输入：",[1825,2902,2903],{},[923,2904,2905],{},"¶cmake ..↵",[1039,2907,2908],{},[923,2909,2910,2911,2914],{},"MinGW 中，请在上述命令中添加 ",[937,2912,2913],{},"-G \"MinGW Makefiles\""," 选项。",[923,2916,2917,2918,2920,2921,2923,2924,2926,2927,2929,2930,2932],{},"就可以运行 CMake。",[937,2919,1525],{}," 代表了 ",[937,2922,2849],{}," 的位置；这里因为是在 build 文件夹中执行，所以 ",[937,2925,1525],{}," 就代表 build 文件夹的上层文件夹——也就是 ",[937,2928,2849],{}," 所处的文件夹。CMake 阅读了 ",[937,2931,2849],{},"，然后在 build 文件夹中生成了一系列文件——其中就包括 Makefile。",[923,2934,2935,2936,2939,2940,2942],{},"既然有 Makefile 了，接下来就可以输入 ",[937,2937,2938],{},"make main"," 命令来生成 ",[937,2941,2634],{}," 可执行文件。这样，我们不用手动编写 Makefile 也能获得良好的多文件编译体验。许多 IDE（如 CLion、VS Code）将 CMake 的操作包装了起来，使得其使用更加方便：这也是我在正文中所介绍的。",[1039,2944,2945],{},[923,2946,2947],{},"在 CMake 诞生之前，大多数程序使用 GNU Autotools 来生成 Makefile。但目前 CMake 已是主流的、成熟的构建生成器，仅有一些 GNU 项目仍在使用 Autotools。虽然话这么说，CMake 仍然出于历史包袱原因饱受批评，也有部分新生项目使用 Xmake、SCons 等构建生成器。",[923,2949,2950],{},"::: tip\n[TODO]\n:::",[2952,2953,2954],"style",{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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":931,"searchDepth":1079,"depth":1086,"links":2956},[2957,2958,2959,2960,2961,2962,2963,2964,2966,2967],{"id":920,"depth":1086,"text":921},{"id":950,"depth":1086,"text":950},{"id":1008,"depth":1086,"text":1008},{"id":1460,"depth":1086,"text":1461},{"id":1715,"depth":1086,"text":1716},{"id":1861,"depth":1086,"text":1861},{"id":1927,"depth":1086,"text":1927},{"id":2246,"depth":1086,"text":2965},"g++ 中的翻译阶段",{"id":2564,"depth":1086,"text":2565},{"id":2839,"depth":1086,"text":2840},"md",null,{},{"icon":6},{"title":13,"description":13},"l04iDlSzCAFrgKUQFiUoIhsXpRXmoAd-kBm_puULUbI",[2975,2976],{"title":5,"path":7,"stem":11,"description":5,"icon":6,"children":-1},{"title":17,"path":18,"stem":19,"description":17,"icon":6,"children":-1},1784618087060]