Skip to content

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 中的每个成员可以是不同的数据类型,成员的类型指定了成员在一块内存中的偏移量。

    c
    struct Person {
      char name[20];
      int age;
      float height;
    };
  • union union 是一种用户定义的数据类型,它允许程序员将不同类型的数据组合成一个单一的实体,并存储在一块较小的连续的内存中。union 中的每个成员可以是不同的数据类型,但是它们共享同一块内存,因此,union 的大小是它最大的成员的大小。

    c
    union 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。

c
struct Demo {
  char a;   //  1
  short b;  //  2
  int c;    //  3
  char *d;  //  8
}

作用域和链接

框架库

Glib

Klib

工程化