> 文章列表 > C语言的深度解析

C语言的深度解析

C语言的深度解析

C语言的深度解析

  • C语言概述
  • C语言内存管理
  • C语言标准库

C语言概述

C是一种通用的、过程式编程编程语言,支持结构化编程、词法作用域和递归,使用静态类型系统,并且广发用于系统软件与应用软件的开发。

C语言具有高效、灵活、功能丰富、表达力强和较高的可移植性等特点,在程序设计中备受青睐,成为几十年来使用最为广泛的编程语言。目前,C语言编译器普遍存在不同的操作系统中,例如:Mocrosoft、Windows、macOS、Linux、Unix等。C语言的设计影响了众多后来的语言,如C++、Java、C#等。现在许多的软件都是由C语言或者其影响和派生的编程语言开发出来的。

与ALGOL的大多数过程式编程语言类似,C语言式一个有结构化程序设计、具有变量作用域以及递归功能的过程式语言。其采用的静态类型系统可以防止无意的程序设计操作。C语言中所有的可执行代码都被包含在子程序(函数)里。其传递参数均是以值传递,另外也可以传递指针。C语言式自由形式语言,即其源代码的缩进并不影响程序的功能,而是使用分号作为语句的结尾,花括号来表示代码块。

由于C语言的语言规模较小,若干高层的机制需要使用定义的函数来提供。如C语言并没有直接处理复合对象(字符串、集合、列表、数组等)的操作,也没有对于存储器分配工具和内存回收工具的直接定义,同时也本身不具有输入和输出以及文件访问的方法。然而,用户定义的函数和C语言标准库中的函数为这些高层的机制提供了可能性。

C语言具有以下特点:

  • 基本数据类型包括字符、整型和浮点数等。另外有派生的个各种数据类型,如指针、数组、结构体和联合。
  • 部分的变量类型可以转换,例如整数型和字符型变量。
  • 通过指针,C语言可以容易的对存储器进行低端控制。
  • 不同的变量类型可以用结构体(struct)组合在一起。
  • 具有基本的控制流:语句组、条件判断、多路选择、循环等。
  • 函数可以返回各种数类型的值,并且都可以递归调用,每次调用函数会重新创建变量。
  • C语言只有32个保留字,使变量、函数名命名有更多的弹性。
  • 编译预处理让C语言的编译更具有弹性。

C语言内存管理

C语言的特色之一是:程序员必须亲自处理内存的分配细节。语言不负责内存边界检查,这是因为在运行时进行内存边界检查会造成性能问题。此特性容易导致缓冲区溢出问题,然而部分编译器(如英特尔编译器)会处于安全性的考量,提供方法以进行运行时内存边界的检查。

大多数C语言实现使用栈(stack)来保存函数返回地址/栈帧基址、完成函数的参数的传递和函数局部变量的存储。然而,在部分极特殊的平台上,使用栈并不能获得最大效率。此时的实现由编译器决定,如果程序需要在运行的过程中动态分配内存,可以利用堆(Heap)来实现。

C程序的元素存储在内存的时候有3种分配策略:

  • 静态分配
    如果一个变量的声明为全局变量或者时函数的静态变量,这个变量的存储将使用静态分配方式(static将变量或函数从栈空间转变为静态区)。静态分配的内存一般会被编译器放在数据段或代码段来存储,具体取决于实现。这样做的前提是,在编译时就必须确定变量的大小。以IA32的x86平台及gcc编译器为例,全局及静态变量放在数据段的低端;全局及静态常量放在代码段的高端。

C语言的深度解析

  • 自动分配
    函数的自动局部变量应该随着函数的返回会自动释放(失效),这个要求在一般的体系中都是利用栈(stack)来满足的。相比于静态分配,这时候,就不必绝对要求这个变量在编译时就必须确定变量的大小,运行时在决定也不迟,但是C89仍然要求在编译时就要确定,而C99放松了这个限制,无论C89还是C99,都不允许一个已经分配的自动变量运行时改变大小。所以说C函数永远不应该返回一个局部变量的地址,要指出的是,自动分配也属于动态分配,甚至可以用alloca函数来像分配堆(Heap)一样进行分配,而且释放时自动的。

  • 动态分配
    还有一种更加特殊的情况,变量的大小在运行时有可能改变,或者虽然单个变量大小不变,变量的数目却有很大弹性,不能静态分配或者自动分配,这时候可以使用堆(Heap)来满足要求。ANSI C定义的堆操作函数是malloc、calloc、realloc和free。使用堆(Heap)内存将带来额外的开销和风险。

C语言标准库

C语言的标准文档要求了一个平台移植C语言的时候至少要实现的一些功能和封装的集合,称为“标准库”,标准库的声明头部通过预处理器命令#include进行引用。

下面以C99标准进行介绍:

文件 简介说明
<assert.h> 断言相关
<ctype.h> 字符类型判断
<errno.h> 标准报错机制
<float.h> 浮点运算
<limits.h> 各种体系结构限制
<locale.h> 本地化接口
<math.h> 数学函数
<setjmp.h> 跨函数跳转
<signal.h> 信号(类似UNIX的信号定义,但是差很远)
<stdarg.h> 可变参处理
<stddef.h> 一些标准宏定义
<stdio.h> 标准I/O库
<stdlib.h> 标准工具库函数
<string.h> ASCII字符串及任意内存处理函数
<time.h> 时间相关
<complex.h> 复数运算
<fenv.h> 用于访问浮点环境以及特定类型
<inttypes.h> 提供整数输入的各种进制转换的宏
<stdbool.h> 提供布尔值
<stdint.h> 更加丰富的整数类型
<tgmath.h> 包括math.h和complex.h函数库