-
使用gdb调试步骤: 1、使用带-g选项的gcc命令编译源文件:gcc -g main.c -o main.out 2、使用gdb工具调试:gdb ./main2.out 3、调试过程中:(gdb): l 列出当前项目源代码(list)→再按l或直接按回车:继续执行上一命令 break 12 将断点打在第12行 start 单步调试 p a 显示当前a的值(print)(当前行的命令未完全执行) n 进入下一行(next) s 进入当前函数内部(step) bt 查看函数堆栈(在上方的函数先执行) f 1 切换到1号栈 q 退出调试查看全部
-
使用指针传参的时候要加‘&’(取地址符)查看全部
-
内存对齐之二篇 cpu对内存的操作有对并的概念: 如果操作1字节的数据,可以是任意地址,如果是操作2字节的数据,如果开始地址在偶数地址,一次就可以取2字节,如果开始地址在奇数,就要2次内存操作才能完成;如果操作4字节的数据,最好开始地址在能被4整除的数值上,这样用一条32位的内存操作指令完成。8字节的开始位置最好的能被8整除的数值上,这样用一条64位的内存操作指令完成。就是说,如果对齐了,一次就可以完成,不对齐,就可能多次才能完成。编译程序处理时也有对齐处理,一般的结构体和对象等估计都有对齐的处理(把结构体或对象的开始位置定在边界上),这样,只要你在结构体里对象之间能处理好对齐,你的数据就能操作得很快。 有时你定义了一个结构体,用了若干字节,但不是8或4的倍数,但你查内存时能发现它们占用的是8或4的倍数(多用了几个字节),就是这个原因。 比如32位机,32根地址线,32根数据线,取数时,cpu的32根据地址线与内存的0-3号地址对齐,cpu的32位的数据线也同样,一个读取周期只能取这0-3地址的3个字节。如果你是取3-4地址的数据,CPU会自动把它分解成2次取数据操作,一次取8位的3单元和一次取8位4单元数据。 只有开始地址是0、4、8...的32位的数据操作才能一次操作完成,内存不支持从1号单元开始的4字节读,CPU和内存的数据线必须相应数据线对齐才行。 如果要没有这个限制,CPU和内存的制作成本就会高一些。况且,CPU和内存的控制总线标准是早就规定好了的,造CPU的生产出了有你这种功能的CPU,但内存不支持,必须某年某月国际上协商出了新的标准,你的这种想法才可能实现。查看全部
-
内存对齐之一篇: 为了加快计算机的取数速度,编译器默认对内存进行字节对齐。对结构体(包括类)进行字节对齐的原则是:1)结构体变量的首地址能够被其最宽基本类型成员的大小所整除;2)结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。 struct SByte1 { double d; // 偏移量 0~7 char j; // 偏移量8 int a; // 偏移量12~15,由于9不能整除4,故先填充9~11 }; sizeof(SByte1); // = 16 struct SByte2 { char j; // 偏移量0 double d; // 偏移量8~15,由于1不能整除8,故先填充1~7 int a; // 偏移量16~19 }; sizeof(SByte2); // = 24,为了凑成8的倍数,填充20~23查看全部
-
变量的本质:内存 指针的本质:地址查看全部
-
指针占用空间大小取绝于系统寻址总线的位数 32位=32bit=4byte 64位=64bit=8byte查看全部
-
栈的内存分配从大到小,函数为于该区域 数据段的内存分配从小到大,全局变量/常量/静态变量位于该区域查看全部
-
同一个函数可以被多次调用,但内部的静态变量是始终不变的查看全部
-
指针:指向的作用,就是地址。内存单元的地址和内存单元的内容是两个不同的概念。change函数不用指针之所以不生效,就是因为内存单元的内容并没有发生交换。改变的只是形参的内存单元内容,但关键的是形参和实参并不是在同一个内存单元。,函数调用是重新为形参开辟了内存单元,调用结束后形参的内存单元就被释放掉!查看全部
-
Array数组其实是一种指针常量,而p则是一种指针变量(数组和指针有一定的通用性,又有一定的差别,指针可以表达数组,而数组不可以表达指针);
p++:指针偏移,运行效率比数组高;
为什么p+4;*p=101 与p[4]=101等价???p[4]=101代表从初始位置(a的地址就始)以四个字节为一步,向前走4步,到达某个位置,然后对这个位置进行初始化赋值,即把101赋给这个地址所代表的内存空间。p[4]代表从初始位置(a的地址就始)以四个字节为一步,向前走4步,到达某个位置。*p=101,代表此时指针指向的地址(即走了四步后所在位置)并对这个地址所在的内存空间进行初始化,赋值为101。
数组名本质是一个数组开头的地址,可以把它赋值给指针变量
int array[n]
int *p=array;
2也是因为这样:它是一个固定的值(指针常量),不可以
array+=2;
指针可以;
p+=2;
查看全部 -
变量名只是代号,变量的本质是内存;
在标准的C语言中,不允许直接对内存地址进行操作,只能是对操作系统已经分配给的内存空间进行操作。(防止用户自己操作内存地址时侵吞系统内存或者其他程序的内存)
int *p=&a; p 指针指向的变量地址; *p 指针指向的变量值; &p 指针自己所在的地址。既然一个指针保存的是变量的地址,对32位CPU,地址有4个字节,就需要4个内存单元来存储,所以每次++p在内存里都是跳4格。
函数调用信息保存在栈(stack)中。 int *pa=&a指将a的地址传给pa。因此p pa看到的是a的地址(&a)。 而p &pa才能看到pa本身的地址。
查看全部 -
对指针类型的变量,gdb: p *指针变量:
如果该地址在栈,堆,数据段,则 会打印该变量的值
如果该地址在代码段,则会打印该变量所指的代码
定义一个函数指针,使用该函数指针(*函数指针)(要传给函数的变量)
查看全部 -
使用调试功能 gcc -g
gdb ---> 断点调试,单点调试
gcc -g 文件名.c -o 文件名.out ---> 使用gdb编译
gbd ./文件名 ---> 开始执行db调试
l:(list)列出源码
回车继续执行刚刚的命令
start ---> 开始执行
break n ---> 截取第n行断点
print或p a ---> 打印输出变量a
n ---> 跳到下一行继续执行
s ---> step 跳入函数
bt ---> 查看函数堆栈
f ---> 切换函数堆
f 1 ---> 跳转到函数1
q ---> 退出调试
查看全部 -
栈:先进后出,后进先出。由高地址向低地址放入,先放入的后出,后放入的先出。
先放入的分配的内存大于后放入的。
字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端两种字节顺序。小端字节序指低字节数据存放在内存低地址处(由右向左),高字节数据存放在内存高地址处;大端字节序是高字节数据存放在低地址处,低字节数据存放在高地址处(由左向右)。
示例中的Linux栈内用的就是小端存储(as高字节存放高地址,由上到下)。
查看全部 -
变量只是一个名称,来表示一个内存的地址的简称,(变量就是内存)
而指针则是将变量(对于我们)与地址本质的转化,
更利于理解。
堆栈段:
1. 为函数内部的局部变量提供存储空间。
2. 进行函数调用时,存储“过程活动记录”。
3. 用作暂时存储区。如计算一个很长的算术表达式时,可以将部分计算结果压入堆栈。
数据段(静态存储区):
包括BSS段(Block Started by Symbol)的数据段。BSS段存储未初始化或初始化为0的全局变量、静态变量,具体体现为一个占位符,并不给该段的数据分配空间,只是记录数据所需空间的大小。数据段存储经过初始化的全局和静态变量。
查看全部
举报