C
C 语言是对汇编语言的一层简单抽象,它将汇编语言中的一些对人类不友好的部分抽象成变量、函数、控制结构(如循环和条件语句)等概念,允许程序员使用一种过程式的代码和语法,并编译成多种汇编代码,屏蔽了大量的硬件平台差异。
变量和数据类型
C 语言中,变量是用于存储数据的内存位置的名称。每个变量都有一个数据类型,用于规定它可以存储的数据类型和大小。C 语言中的基本数据类型包括:
char 代表一个字符,通常占用 1 个字节,8个 bit 位,其取值范围是 -128 到 127 或 0 到 255。一般地,字节操作符使用 unsigned char 类型。
int 代表一个整数,通常占用 4 个字节,32个 bit 位,其取值范围是 -2147483648 到 2147483647,即 -2^31 到 2^31 - 1,unsigned int 的取值范围是 0 到 4294967295,即 0 到 2^32 - 1。
long long 代表一个长整数,
float 单精度浮点数,通常占用 4 个字节,32个 bit 位,其取值范围是 1.2E-38 到 3.4E+38,精度是 6 位有效数字。
double 双精度浮点数,通常占用 8 个字节,64个 bit 位,其取值范围是 2.3E-308 到 1.7E+308,精度是 15 位有效数字。
enum 枚举是一种用户定义的数据类型,它允许程序员为整数常量定义符号名称。与其他高级语言不同,C 语言中的枚举类型是整数类型,其取值范围是 -128 到 127 或 0 到 255,同时,枚举的名字会污染全局命名空间。
struct struct 是一种用户定义的数据类型,它允许程序员将不同类型的数据组合成一个单一的实体,并存储在一块较大的连续的内存中。struct 中的每个成员可以是不同的数据类型,成员的类型指定了成员在一块内存中的偏移量。
cstruct Person { char name[20]; int age; float height; };
union union 是一种用户定义的数据类型,它允许程序员将不同类型的数据组合成一个单一的实体,并存储在一块较小的连续的内存中。union 中的每个成员可以是不同的数据类型,但是它们共享同一块内存,因此,union 的大小是它最大的成员的大小。
cunion Data { int i; float f; char str[20]; };
void void 是一种特殊的类型,它表示没有值或没有类型。void 通常用于函数的返回类型,表示函数不返回任何值,或者用于函数的参数列表,表示函数不接受任何参数。
typedef 关键字用于为现有的数据类型创建新的名称,以便在代码中更方便地使用。例如,typedef int INT,这样就可以在代码中使用 INT 来代替 int。
字面量
整数字面量
- 十进制数字面量:10、-20
- 八进制数字面量:012、-017
- 十六进制数字面量:0x1A、-0xFF
- 无符号数字面量:10u、20U
- 长整型数字面量:10L、20l
- 无符号长整型数字面量:10UL、20ul
浮点数字面量:
- 单精度浮点数字面量:3.14f、-2.718f
- 双精度浮点数字面量:3.14、-2.718
- 无符号浮点数字面量:3.14u、-2.718u
- 长双精度浮点数字面量:3.14l、-2.718l
- 无符号长双精度浮点数字面量:3.14ul、-2.718ul
- 指数浮点数字面量:3.14e2、-2.718e-3
- 无符号指数浮点数字面量:3.14ue2、-2.718ue-3
字符字面量:
- 单字节字符:'a'、'b'、'\n'
- 转义字符:'\n'、'\t'、'\0'、'''、'"'、'\'
由于 char 类型是 1 个字节,所以它只能表示 256 个字符,一个 char 字面量等价于一个 0-255 的整数,也就是其 ASCII 码值,常见字符的对应 ASCII 码值如下:
- 'a':97
- 'A':65
- '0':48
- ' ':32
- '\n':10
- '\t':9
- '\0':0
字符串字面量:
- 字符串字面量:"hello"、"world"
指针字面量:NULL
布尔字面量:true、false
字节序
运算符
- 算术运算符:+、-、*、/、%
- 关系运算符:==、!=、<、>、<=、>=
- 逻辑运算符:&&、||、!
- 位运算符:&、|、^、~、<<、>>
- 赋值运算符:=、+=、-=、*=、/=、%=、<<=、>>=、&=、|=、^=
控制结构
- if-else 分支
- switch-case 分支
- while 循环
- for 循环
- goto 跳转
函数
函数是一段可重复使用的代码块,它接受输入参数,执行一些操作,并返回一个结果。函数可以接受多个参数,也可以不返回任何结果。函数需要定义在一个文件中,并在其他文件中调用。
指针
内存管理
结构体内存对齐
为什么需要内存对齐?
从时间的角度讲:现代 CPU 访问内存时,通常按照 字节对齐(byte alignment) 的方式进行:32 位系统:CPU 一次读取 4 字节,所以变量最好对齐到 4 字节。64 位系统:CPU 一次读取 8 字节,所以变量最好对齐到 8 字节。如果变量没有对齐,CPU 可能需要多次访问内存,导致性能下降,甚至某些 CPU 可能会报错(如某些 RISC 体系结构)。
从空间的角度讲:C 可以强制要求结构体的对齐方式,使得结构体的成员紧凑,从而达到节省内存的目的,但是,如果访问内存的时候跨越了 4 字节或者 8 字节,那么就会造成速度下降,这是一个 tradeoff。
struct Demo {
char a; // 1
short b; // 2
int c; // 3
char *d; // 8
}