C语言if 与 switch 原理区别if-else结构灵活支持复杂的判断语句在条件可预测的情况中将更常触发的if放在考前位置效率会好一点点switch的判断条件开销均衡但判断条件只能是类整型常量。当case数量3个时会有优化其实现结构有4种其中第二种方案是当条件大概是线性的时(比如条件分别是1 9 2 6 4 3 排序后1 2 3 4 6 9)收集每个case的代码起始地址用他们的地址做一个表(数组)switch条件是多少就读取表对应的内存地址然后直接跳转到地址所在的代码区执行直到遇到jmp(break)没有jmp跳转的话就会继续执行到相邻的下一个case穿透defalt可以写在多个case中间也没问题汇编代码会按照C代码的书写顺序编写汇编指令。红框就是建立的那个数组的基地址循环执行效率最高的是do while 最低的是for循环解决线性问题更方便非线性问题往往用递归更容易解决函数调用实现数据存储是栈结构根据栈增长方分为0地址增长(栈顶为0到0则栈溢出x86架构就是) 或 高地址增长调用约定调用方 与 被调用方需要约定1.参数传递方向(参数列表多个参数是从左到右还是相反)2.传输媒介(栈 或 寄存器)3.返回值在哪里4.调用方 或 被调用方 谁来清理参数占用的内存举例__cdecl: 从右往左传参传输媒介为栈返回值在寄存器调用方释放参数空间 (通用)__stdcall:从右往左传参传输媒介为栈返回值在寄存器被调用方释放参数空间 (通用)__fastcall:左数前两个参数寄存器传其他用栈传(从右往左)返回值在寄存器被调用方释放参数空间 (微软)int__cdeclFun(inta,intb)//返回值与函数名之间写调用约定编辑器根据所选编译选项会自动填写因此往往可以省略保存返回地址保存调用方的栈信息为将来回到调用方保存必要的信息也就是前一个函数的栈顶更新当前栈底到栈顶函数执行完要回恢复到前一个栈函数的栈顶也就是当前函数的栈底保存调用方的栈底将调用方的 ebp 压栈然后将当前 ebp 指向当前栈顶。恢复调用方的栈帧函数返回前将 esp 恢复为 ebp 的值再弹出保存的调用方 ebp使栈顶回到调用方的栈顶。为局部变量申请空间抬高栈顶多的部分就是放了局部变量保存寄存器环境把之前函数使用的寄存器原值保存方便将来调用结束出栈时恢复上一个函数的寄存值数据(最多只有3个 ebx, esi, edi)/ZI /Zi 调试选项如果启用了调试信息开关将局部变量初始化为0xcccccccc(烫烫烫烫)未启用则没有这一步执行函数体举例main函数数据的栈结构栈里存的都是 局部变量 和 参数变量函数调用结束后将以上步骤逻辑反这来一次就可以了1.恢复原寄存器数据2.释放局部变量空间3.得到调用方的栈地址4.按照不同的调用约定相反操作__cdecl 返回到刚刚拿到的调用方的栈地址的地方现在就相当于主人换成了调用方当前栈顶就是刚刚执行完成的函数返回值的地址调用方清理参数空间其他约定就 拿到调用方地址后先清理参数空间再返回到调用方地址。执行完毕如此也能很直观的理解递归为什么占内存了每调用一次自身就开了一次栈空间要是退出逻辑没写好很容易就栈溢出了。除了栈数据在内存种还有以下几个分区data区全局变量 静态变量 常量0x0042开始已初始化数据区0x0042开始只读区常量可读可写区全局变量 静态变量vc6编译的exe会将已声明的变量内容放在exe中程序运行时就会把该数据拿到发在程序模块基地址0040000(vc6可设基地址必须是页边界且不能是内核的和已占用的那些地址)未初始化数据区未初始化的变量在0x0046堆代码区机器代码ps: if for 后只有一行逻辑时花括号{}可以省略但不建议因为当这一行是宏而宏的内容有多行时执行结果就不是预期的样子了。goto 语句后边跟的标号有时会看到两个标号相减的逻辑这其实是在求段代码的长度。