c只是底层硬件的简单的抽象。只要底层硬件体系结构没有革命性的变革,c语言就不会被淘汰!
c与汇编相关的工具的使用(将c语言程序生成16位,32位,64位的汇编程序):通过相互间代码的对比分析,来深入理解汇编级底层的程序设计模型(寄存器,内存单元,I/O端口,指令系统,寻址方式,程序映像)以及在这基础上各种c语言的概念。
1、将c语言程序汇编成16位的实模式汇编程序。使用早期的c语言开发环境Turbo C中的编译器TCC。
对应的命令:tcc -s 源程序 自动生成和源程序同名的
2、将c语言程序汇编成32位或者64的汇编程序.使用64位Dev-C++环境下的gcc编译器
对应的命令:
1)将.c的源程序汇编链接生成32位的exe程序:gcc t.c -o t.exe -m32
将.c的源程序汇编链接生成64位的exe程序:gcc t.c -o t.exe
2)将exe可执行程序反汇编成对应的编译指令:
反汇编成intel风格的汇编指令:objump -D t.exe > t.s -M intel
反汇编成linux风格的汇编指令:objump -D t.exe > t.s
3) 直接由.c的源码生成对应的汇编指令: 生成32位的Intel风格的汇编指令:gcc -S t.c -o t32.s -m32 -masm=intel
生成32位的Linux风格的汇编指令:gcc -S t.c -o t32.s -m32
生成64位的Intel风格的汇编指令:gcc -S t.c -o t64.s -masm=intel
生成64位的Linux风格的汇编指令:gcc -S t.c -o t64.s
用as命令可以将生成的.s的汇编程序(gcc -S生成的汇编程序)汇编成.o的二进制目标程序(还没有链接库的代码)将32位的.s汇编程序生成32位的目标代码:as t32.s -o t32.o --32
将64位的.s汇编程序生成64位的目标代码:as t64.s -o t64.o
利用命令objdump -d t64.o -M intel > t64o.s 可以将二进制目标代码.o反汇编成汇编代码。
利用命令objdump -d t32.o -M intel > t32o.s 可以将二进制目标代码.o反汇编成汇编代码。
3、c语言程序的完整的开发过程:
c程序的基本结构:由一个或多个函数构成,main函数是程序的入口和整个流程的组织者,它直接或间接调用别的函数来辅助完成整个程序的功能。这些函数分布在一个或多个.c的源文件中,每个称为一个可编译单元。
(1) 编辑源程序
(2) 编译预处理:gcc -E t.c -o t.i (包含头文件,宏替换等预处理工作)
(3) 编译(只编译,不链接):gcc -c t.c -o t.o -m32 (生成32位的目标代码)
可以看成两步:
gcc -S t.c -o t.s -m32 -masm=intel
as t.s -o t.o --32
(4) 链接库函数的代码,生成最后的可执行程序:gcc t.o -o t.exe -m32(生成32位的可执行程序)
4、c语言中的一些核心概念:数据组织+数据处理。 数据类型:Data Type1、占的存储单元数不一样(表示范围不一样);//c语言中运算符sizeof可以用来查找某种类型数据的内存字节数。
2、存储表示的编码格式不一样:整数(二进制补码),浮点数(IEEE754标志),英文ASCII码,汉字内码,java Unicode编码
3、允许的操作不一样。
常量(Constants):在程序执行过程中不发生改变的量。
常量的类型:
1、直接常量:32,0.25,“hello”; //int i = 32;--->mov [ebp+32] ,32 ;指令加载到代码段(只读的)
2、符号常量:#define PI 3.1415926 //处理在编译预处理阶段完成,直接进行符号名替换
前两种常量缺乏类型信息,容易出错。
3、常变量:const int N = 10; //用编译器进行编译检查保证在后面的源码中没有直接更改该数据量的值。
N可以取地址,也有类型信息,通过const关键字来告诉编译器,去检测后面的源码,如果有代码试图修改N的值,则编译保错。
但是const修饰的变量不能完全保证其值不被修改!可以通过指针等间接手段来修改它的值。
变量(Variable):变量就是内存单元的抽象(早期的可能是CPU中寄存器的抽象)。
可以通过赋值语句修改该存储单元的值。
变量的属性:变量名(本质就是数据的地址)、类型、地址(用&取变量的地址)、变量的值(初始值)、存储类别(storage class):生存期lifetime,作用域scope。
存储类别:变量存储在什么地方?cpu内的寄存器;全局数据段;栈,堆。cpucpu内的寄存器(c语言中由register这个关键字,建议编译器把变量来放到寄存器中以提高访问效率);
全局数据段(全局变量和静态局部变量,加载时就分配存储空间,并且初始化,直到程序退出时才回收空间);
栈(函数内部定义的非静态局部变量,运行时再由程序员定义的赋值语句进行初始化,否则不会初始化);
堆(malloc函数动态申请,通过指针访问。
变量在使用前一定要初始化!初始化的时机:是装载时初始化,还是执行时再初始化;是自动初始化还是必须程序员自己手动初始化。
例如:全局变量和静态局部变量是在装载时由编译程序和装载程序自动初始化的!如果没有显式的初始化,则自动初始化为0值(默认初始化),否则初始化为程序员指定的值(显示初始化)。
特别注意:但是在函数内部定义的非静态局部变量,不会自动初始化(其值是随机的,取决于内存单元当时的值),必须程序员在使用前自己初始化(使用赋值语句)。
变量在使用前一定要初始化!(两个问题:1、什么时机初始化?2、会不会自动初始化?)