首页 > 编程语言 >C语言笔记 | C与汇编

C语言笔记 | C与汇编

时间:2022-10-28 14:44:30浏览次数:53  
标签:汇编 int 局部变量 笔记 C语言 宽度 数组 类型 指针

函数

  • 通过栈传递参数
  • 平衡栈(函数调用约定)
    1. cdecl
      • 参数从右至左入栈
      • 调用者清栈
    2. stdcall
      • 参数从右至左入栈
      • 自身清栈
    3. fastcall:
      • ecx和edx传前两个参数, 剩下的参数从右至左入栈
      • 自身清栈
  • 提升栈使用EBP寻址, 函数内使用提升后的"新"栈
    • 提升: 将原EBP地址压入栈, 使用EBP存储原ESP地址, 提升ESP
    • 下降: 将ESP复原, 取出EBP并复原
  • 返回值使用EAX传递

变量

  • 变量类型确定内存宽度
  • 变量名是内存地址的别名

全局变量

  • 每个全局变量有一个固定的独一无二的内存地址
  • 全局变量在编译的时候就已经确定了内存地址和宽度
  • 如果不重新编译, 全局变量的内存地址不变
  • 全局变量中的值任何程序都可以修改, 是公用的
  • 全局变量有默认值

局部变量

  • 局部变量是函数内部申请的, 如果函数没有执行, 那么局部变量没有内存空间
  • 局部变量的内存是在栈中分配的, 程序执行时才分配(我们无法预知函数何时执行, 这意味着无法确定局部变量的内存地址)
  • 因为局部变量的内存是不确定的, 所以只能在函数内部使用, 其他函数不能使用
  • 局部变量定义后必须初始化值

整数类型

  • 十转二: 除二取余(整数位继续除直到0, 小数位0与非0为二进制), 能保证精度
  • 使用补码存储
  • 如果数据溢出(超出范围), 将舍弃高位(截断)

浮点类型

  • 十转二: 乘二取整(小数位继续乘直到0, 整数位为二进制), 不能保证精度
  • 存储方式:
    1. float(32bit):
      • 31-30(1bit): 符号位
      • 30-22(8bit): 指数部分(第一位是科学计数法方向位, 小数点向左移是1, 向右移是0)
      • 22-0(23bit): 尾数部分
    2. double(64bit):
      • 63-62(1bit)
      • 62-51(11bit)
      • 51-0(52bit):
  • 编码步骤:
    1. 转为二进制小数
    2. 使用科学计数法表示
    3. 按编码规则填入
  • 栗子:
    • 8.25->1000.01->1.00001*2^3->0 10000010 00001000000000000000000
    • 16进制: 41040000

类型转换

  • 小转大: MOVSX(带符号)/MOVZX(不带符号)
  • 大转小: 使用小寄存器EAX/AX/AL

运算

分支语句

  • switch的效率比if-else高
    • switch在大于3个分支时, 将跳转地址存入内存, 使用jmp计算跳转
    • switch生成一张连续跳转表, 如果不连续则填充default地址, 将x减去分支中的最小值, 大于分支数则跳default, 否则映射到跳转表jmp [计算值*4+跳转表地址]
    • if-else是遍历条件执行

数组

数组越界问题

  • 数组下标+2(从栈顶开始)可以用下标找到[ebp+4]

多维数组

  • 内存连续的一维数组
  • 第1个下标表示第几个数组, 第2个下标表示每个数组中的第几个元素
  • 第1个下标每加1相当于内存中加上每个数组的长度
  • 二维数组与一维数组的映射: 从0-N所在的一维数组之间的数组个数乘一维数组的长度加上N

转换

二位数组坐标转一维数组坐标

指针

  1. 指针类型的变量宽度永远是4字节(32位)
  2. 指针类型的变量加减运算的实际宽度是它基础类型的宽度(寻址宽度)(去掉一个*)
    1. char* a = (char*) 1; a++; //a实际加了1
    2. int* b= (int*) 1; b++; //b实际加了4
    3. char** c (char**) 1; c++; //c实际加了4
  3. 取地址(&):
    1. 局部变量: lea eax, dword ptr ss:[ebp-4]
    2. 全局变量: mov eax, 00426d9c
  4. 取值(*):
    1. 读: mov eax, dword ptr ds:[eax]
    2. 写: mov dword ptr ds:[eax], 1
    • 取值后的类型是指针类型去掉一个*的类型, 栗如int (*)[2]类型取值的类型是int [2]

字符串

  1. char a[] = {'A', 'B', '\0'}
    • 直接赋值数组(没有常量区字符串, 数组可修改)
  2. char b[] = "AB"
    • 将字符串放到常量区
    • 将字符串复制到数组(有常量区字符串, 数组可修改)
  3. char* c = "AB"
    • 将字符串放到常量区
    • 将地址给c(有常量区字符串, 字符串不可修改)

指针与指针指向的类型没有关系

struct st {
    int a;
    int b;
}

int arr[8] = {1, 2, 3, 4, 5, 6, 7, 8};

struct st* sx = (struct st*) arr;

for (int i = 0; i < 4; i++) {
    printf("%d %d\n", sx->a, sx->b);
    sx++;
}

数组与数组指针类型

  • 数组是数组类型(type [length]), 不是数组指针类型(type (*)[length]), 只是数组类型的值是地址
    • 数组类型(数组名)增减是数组内数据类型的宽度
    • 数组指针类型(&数组名)增减是数组宽度(数组长度*数据类型宽度)

栗子: 二维数组只是表象

  • 数组指针的维度与数组的维度没有关系

指针偏移取一维数组类型

int a1[6] = {5, 6, 7, 4, 3, 2};
int (*p)[3] = (int (*)[3]) &a1;
  • p的宽度是3(对于int数组来说), p[1]等于*(p + 1), 位置+3到"4"的位置
  • *(p + 1)取值得到int数组类型, 再偏移取值p[1][1]或((p + 1) + 1)

二维数组类型

int a1[6] = {5, 6, 7, 4, 3, 2};
int (*p)[2][3] = (int (*)[2][3]) &a1;
  • *p得到二维数组类型, 操作二维数组类型取值(*p)[1][1]

指针偏移取二维数组类型

int a1[8] = {5, 6, 7, 4, 3, 2, 1, 8};
int (*p)[2][2] = (int (*)[2][3]) &a1;
  • p的宽度是4(对于int数组来说), *(p + 1)使位置到"3"的位置
  • *(p + 1)取值得到int二维数组类型, 对后四个数操作, (*(p + 1))[1][1]

结构体

  • 对结构体的操作并不是转为指针操作(数组), 而是结构体类型
    1. 结构体作为函数参数将进行传值(所有成员)而不是传地址
      • 传一个四个成员的结构体与传四个参数没有区别
    2. 结构体的相互赋值将拷贝所有结构体成员
  • 问题: 大量的内存复制
    • 使用指针传递结构体

标签:汇编,int,局部变量,笔记,C语言,宽度,数组,类型,指针
From: https://www.cnblogs.com/nancimua/p/16836035.html

相关文章

  • 《STL源码剖析》阅读笔记 1
    推荐先看YOUTUBE上STL源码侯捷的视频,再对STL有了一定的了解的基础上,再结合书籍阅读源码.【我先去看视频了,等看完了,再回来补充阅读笔记】源码:SGISTLhttps:/......
  • C语言习题:使用指针交换两个变量的数据
    题目在主程序通过键盘输入两个正整数,编写并调用自定义函数voidswap(int*x,int*y)实现两个整数变量值的交换并输出交换后的结果。代码#include<stdio.h>voidswap(......
  • 笔记:emmet语法
    emmet语法笔记:在写代码工具中快速生成HTML结构语法:以div为例:1、快速生成标签,下载autoclosetag插件,输入div然后回车,自动添加关闭标签;2、同时生成多个同级的相同标签:di......
  • Pytorch----入门级CIFAR10的神经网络层,sequential,tansorboard可视化卷积中的各种参
    文章目录​​普通方法​​​​完整代码:​​​​sequential方法​​​​使用tansorboard可视化卷积层中的各种数据​​普通方法使用神经网络:(CIFAR10的神经网络)可以看到......
  • Pytorch----池化层(平均值池化、最大值池化、自适应最大值池化)--入门级小实例(逐行注
    文章目录​​最大值池化层​​​​平均值池化层​​​​自适应平均值池化层​​​​代码实现​​还是用上次的小实例,这次加入三种池化层做练习。关于池化层的基础概念可以......
  • 数论-费马小定理 学习笔记
    1.定理内容如果p是一个质数,而整数a不是p的倍数,则有。即:若为素数,,则。第二种表述形式:对于任意整数,有。在实际的应用中,我们最多用的是第二种表述形式。2.证明设一个质数为......
  • 数论-欧拉函数 学习笔记
    一、欧拉函数1.欧拉函数的定义欧拉函数(Euler’stotientfunction),即,表示的是小于等于和比如说。当n是质数的时候,显然有。2.欧拉函数的一些性质欧拉函数是积性函数。......
  • 汇编语言-8086指令(上)
    数据传送指令汇编语言中字母开头通常表示标识符(如常量、变量、标号),所以MASM规定十六进制数如果以字母开头需要添加前导0。当目的操作数是存储单元,而源操作数既可以是字又......
  • java8-笔记
    获取某个字段的值List<Integer>num=modelList.stream().map(model::getID).collect(Collectors.toList());根据某个字段去重再获取某个字段的值。List<CallBillModel......
  • FX3U+BCNET-FX实操笔记
                 ......