1.C语言简介
2. 一个简单的例子 hello world
#include<stdio.h>
#define PI 3.14
int main()
{
// 安装了MinGW环境, 使用gcc编译器, 用notepad++左右视图方式打开(左视图hello.c, 右视图hello.i)
// 用cmd打开Dos模拟器, 执行命令 C:\>gcc -E hello.c -o hello.i 预处理文件,用另一视图打开,观察hello.i文件
printf("hello world\n");
printf("hello %lf\n", PI); // 宏替换
//printf("hello world\n") // 预处理不会检查错误(行尾没有分号)
#if 0
printf("hello world\n"); // 此行内容不会编译, 因为0在C语言中表示false
#endif
#if WIN32
printf("hello WIN32\n");
#endif
#if WIN64
printf("hello WIN64\n"); // #if 也可用于长文注释
#endif
#if abc
printf("hello abc\n"); // #if 条件编译 - 默认并不会编译此行,需要加"-D"参数 gcc -E hello.c -o hello.i -Dabc 如此才会编译
#endif
return 0;
}
3. GCC编译过程
C程序编译可执行程序4步:
-
预处理
hello.i带 "#" 的语句是预处理指令, 预处理指令在预处理阶段就进行处理了, 预处理:
gcc -E hello.c -o hello.i-
头文件展开:
#include <stdio.h>包含了stdio.h(预处理时将stdio.h文件拷贝至预处理文件中) -
宏替换(宏定义展开):
#define代表声明一个宏, 在预处理阶段会将宏替换, 如: #define PI 3.14 会将 PI 全部替换为 3.14 -
条件编译: 条件不成立:
#if 0 ... #endif, 条件成立:#if 1 ... #endif, 条件参数(在编译时指定):#if abc ... #endif -
删除注释
-
不检查语法错误
条件编译 -
#if abc ... #endif默认并不会编译此代码块, 需加"-D"参数才会进行编译如:gcc -E hello.c -o hello.i -Dabc -
-
编译
hello.s检查语法, 将预处理后文件编译生成汇编文件, 编译:
gcc -S hello.i -o hello.s -
汇编
hello.o将汇编文件生成目标文件(二进制文件)
-
链接
设置运行环境, 堆栈等, 链接其他库 (C语言写的程序是需要依赖各种库,所以编译之后还需要把库链接到最终的可执行程序中去)
| 选项 | 含义 |
|---|---|
| -o file | 指定生成的输出文件名为file |
| -E | 只进行预处理 |
| -S(大写) | 只进行预处理和编译 |
| -c(小写) | 只进行预处理、编译和汇编 |
预处理:gcc -E hello.c -o hello.i
编 译:gcc -S hello.i -o hello.s
汇 编:gcc -c hello.s -o hello.o
链 接:gcc hello.o -o hello
4.helloworld程序解析
#include <stdio.h> // #:关键标识符,表示引入头文件; include: 引入头文件关键字
// stdio.h: 系统标准输入、输出库对应的头文件, 给printf()函数服务
// #include <...>: 尖括号表示是系统库函数; #include "...": 双引号引起来的表示是用户自定义函数
int main(void) // int表示函数返回值类型是整数类型; main: 函数名,main函数也叫主函数 整个程序中仅且只有一个main函数,程序从main函数开始执行(程序唯一入口,必须有,且只有1个); void表示函数调用无需传参
{ // {左大括号: 函数体起始位置
printf("hello world\n"); // 将 "hello world" 打印到屏幕上; \n: 转义字符, 表示回车换行 new line
system("pause"); // 调用system函数, 实现暂停功能
return 0; // 返回当前函数调用 -- 退出程序. 0要跟main()函数的返回值 一一对应
} // }右大括号: 函数体结束位置
5.system()函数
作用: 在程序中启动另一个程序 参数:要的是待启动程序的路径名
#include <stdio.h>
#include <stdlib.h>
int main()
{
//syetem启动程序,如果这个程序系统可以找到,不用加路径,
//如果环境变量找不到,需要加路径
//windows路径以\\ 或 /
//system("mspaint");//启动画图板
//system("C:\\Users\\Administrator\\Desktop\\c++13\\hello.exe");
system("C:/Users/Administrator/Desktop/c++13/hello.exe");
printf("hello worldfbahfoahfoooooooooooooooooooooo\n");//打印到终端
return 0;
}
6.CPU内部结构与寄存器(了解)
32位CPU是32位地址总线 2^32, 最大仅支持4GB内存
2^32
2^10 * 2^10 * 2^10 * 2^2
1024 * 1024 * 1024 * 4
1k = 1M = 1G = 4G
-----------------------------------------------
2^64
2^10 * 2^10 * 2^10 * 2^10 * 2^10 * 2^10 * 2^4
1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 16
1k = 1M = 1G = 1T = 1P = 1EB = 16EB
寄存器 缓存 cpu 内存之间的关系: cpu > 寄存器 > 缓存 > 内存
寄存器名字
| *8位* | *16位* | *32位* | *64位* |
|---|---|---|---|
| A | AX | EAX | RAX |
| B | BX | EBX | RBX |
| C | CX | ECX | RCX |
| D | DX | EDX | RDX |
寄存器、缓存、内存三者关系
按与CPU远近来分,离得最近的是寄存器,然后缓存(CPU缓存),最后内存。
CPU计算时,先预先把要用的数据从硬盘读到内存,然后再把即将要用的数据读到寄存器。于是 CPU<--->寄存器<--->内存,这就是它们之间的信息交换。
那为什么有缓存呢?因为如果经常操作内存中的同一址地的数据,就会影响速度。于是就在寄存器与内存之间设置一个缓存。
因为从缓存提取的速度远高于内存。当然缓存的价格肯定远远高于内存,不然的话,机器里就没有内存的存在。
由此可以看出,从远近来看:CPU〈---〉寄存器〈---〉 缓存 〈---〉 内存。
【扩展内容】位, 字节, 字的区别
- 位(bit) 二进制位,
计算机内部数据储存的最小单位, 11010100是一个8位二进制数。一个二进制位只可以表示0和1两种状态(2^1), 两个二进制位可以表示00、01、10、11四种(2^2)状态, 三位二进制数可表示八种状态(2^3)... - 字节(byte) 字节来自英文Byte,习惯上用大写的“B”表示。
计算机中数据处理的基本单位。计算机中以字节为单位存储和解释信息,规定一个字节由八个二进制位构成,即1个字节等于8个比特(1Byte=8bit)。八位二进制数最小为00000000,最大为11111111;通常1个字节可以存入一个ASCII码,2个字节可以存放一个汉字国标码。 - **字(word)**计算机进行数据处理时,一次存取、加工和传送的数据长度称为字(word)。一个字通常由一个或多个(一般是字节的整数位)字节构成。例如286微机的字由2个字节组成,它的字长为16;486微机的字由4个字节组成,它的字长为32位机。 计算机的字长决定了其CPU一次操作处理实际位数的多少,由此可见计算机的字长越大,其性能越优越。
一个ascll码就是一个字节, 因为ascll码的二进制范围是00000000到11111111, 十进制范围是0到255,
// 扩展内容
一、定义
1、位/比特(bit)
位/比特(bit)是计算机中最小的数据存储单位。二进制中每一位的状态只能是0或1。
2、字节(byte)
字节(byte)由8位(bit)组成,是存储空间的基本计量单位,通常1个字节可以存储半个汉字或1个英文字母。
3、字(word)
字(word)是计算机进行数据存储、处理和运算的单位,由若干个字节(byte)组成。字的位数叫字长,不同处理器性能的计算机中字长不同,例如32位处理器中,1字=32位=4字节,64位处理器中,1字=64位=8字节。
二、相互转换
1B(byte,字节)= 8 bit;
1KB(Kibibyte) = 2^10 B = 1024 B;
1MB(Megabyte) = 2^10 KB = 1024 KB = 2^20 B;
1GB(Gigabyte) = 2^10 MB = 1024 MB = 2^30 B;
1TB(Terabyte) = 2^10 GB = 1024 GB = 2^40 B;
1PB(Petabyte) = 2^10 TB = 1024 TB = 2^50 B;
1EB(Exabyte) = 2^10 PB = 1024 PB = 2^60 B;
1ZB(Zettabyte) = 2^10 EB = 1024 EB = 2^70 B;
1YB(Yottabyte) = 2^10 ZB = 1024 ZB = 2^80 B;
1BB(Brontobyte) = 2^10 YB = 1024 YB = 2^90 B;
1NB(Nonabyte) = 2^10 BB = 1024 BB = 2^100 B;
1DB(Doggabyte) = 2^10 NB = 1024 NB = 2^110 B;
1CB(Corydonbyte) = 2^10 DB = 1024 DB = 2^120 B;
1XB(Xerobyte) = 2^10 CB = 1024 CB = 2^130 B;
详见两篇文章: