链接属性
(1)大家知道程序从源代码到最终可执行程序,经历的过程:编译、链接。
(2)编译阶段就是把源代码搞成.o目标文件,目标文件里面有很多符号和代码段、数据段、bss段等分段。符号就是编程中的变量名、函数名等。运行时变量名、函数名能够和相应的内存对应起来,靠符号来做链接的。
(3).o的目标文件链接生成最终可执行程序的时候,其实就是把符号和相对应的段给链接起来。
C语言中的符号有三种链接属性:外连接属性、内链接属性、无连接属性。
一.c程序的内存映像:
整个4G的内存分配。
1.代码段&只读数据段:
代码段:是存放整个代码(函数)。只读数据段:在程序运行的时候只能读数据,不能改数据比如const 关键字修饰的变量。
2.数据段和bss段:
数据段:初始化非零的全局变量和static修饰定义的非零的局部变量。
bss段:未被初始化的全局变量和static修饰未被初始化的变量。
3.文件映射区:
当一个进程打开文件时,就直接在内存中改变文件内容,就是把硬盘里的文件复制了一份在内存中,修改完成后保存后就将内存中写到硬盘里去。
4.堆:用mocall申请内存。free释放内存。如果没有释放,内存就泄露了,是程序员手工操作的。
5.栈:局部变量,随取随用。函数的调用也涉及到栈。
6.内核映射区:将操作系统的内核程序映射到该区域了。
二.关键字:
1.auto:跟局部变量的使用没有区别。加不加无所谓。
2.static:两种用法:这两种用法完全不同。很有迷惑性。。。。重要。
(1)修饰局部变量,形成静态的局部变量,他的内存分配在 数据段/bss,此时对比局部变量,他的内存分布在栈上。(存储 类不同就衍生出许多不同)这就和局部变量上有了本质差别。(作用域、链接属性、生命周期)作用域都是代码块 { }
(2)修饰全局变量,形成静态的全局变量,静态全局变量和全局变量有什么区别。他们的区别就在链接属性上了。
静态局部变量存储类和全局变量相同,作用域是代码段。而全局变量是整个文件。
静态局部变量连接属性是无连接。全局变量是外连接。
3.extern:
声明作用。 在a.C中的定义的全局变量,想要在b.C中用。就要用extern声明该全局变量。不然就会没定义。
4.volatile:
易变的。有时候在程序中(isr中断服务程序、共线程、硬件自动置位)会改变某个变量的值。但是编译器会帮我们优化程序。比如
a=1;
b=a;
c=b; //编译器会帮你优化成 c=b=a=1;
不会逐一去赋值,cpu执行效率高了。但是编译器并不知道,他是没有这个意识的,所以要加volatile 关键字。编译器就会知道不去优化。如果是下面的这样代码,就会出错。
do
{
*p=1;
}
while(*p) //*p的值有可能会被改,但是如果没加volatile关键字的时候,编译器就会将其优化成while(1)死循环。
但是加了volatile关键字时,编译器就不会将其优化成while(1),而是写成这样 while(*p)
5.restrict:只用来修饰指针。如果加了restrict关键字,该指针指向的内存空间只能由该指针修改别的指针无法修改。
二、作用域
局部变量:
全局变量:
重名变量的掩蔽规则:
三、生命周期:
栈上的分配的变量:函数每调用一次都会创建一次,然后使用,最后在函数返回的时候消亡。
堆上分配的变量:malloc申请时诞生,然后使用,直到free是消亡。
代码段&rodata段:
链接属性:程序的生成过程:编译加链接。编译是为了将函数/变量等.O二进制机器码文件,链接是为了把第各个独立的二进制的.o链接形成一个可执行程序。
编译是以.c文件为单位,链接是以工程为单位,
(1)
(2)
三种链接属性:
外链接,内连接,无连接。
(1)外链接外部链接属性,再整个程序范围内(可以跨文件)进行链接,比如普通的全局变量和函数。
(2)内连接:static修饰的全局变量的函数。在本文件中。
(3)无连接:所有的局部变量。
函数和全局变量重名问题:C语言就是用三种链接属性来解决重名
我们将明显不会在其他C文件中应用(只在当前文件中应用)的函数/全部变量,加static变为内连接。
static 修饰的全局变量和全局变量的区别:将全局变量的外链接改为内连接。注意和static 修饰局部变量 改变的是存储类。
如果在某个.c文件中写程序时
最后总结:将学习的内容总结:要学会总结,自己每次学完后要学会写总结:这样才会更好的学习新知识。---谨记---