C语言
C语言(英語:C Language)是一种通用的、过程式编程程式語言,支持结构化编程、词法作用域和递归,使用静态类型系统,并且广泛用于系统软件与应用软件的开发。
《C程序设计语言》,第一部介绍C语言的书籍 | |
程序式指令式编程(过程式)、结构化编程 | |
設計者 | 丹尼斯·里奇(Dennis Ritchie) |
實作者 | 丹尼斯·里奇(Dennis Ritchie)和肯·汤普逊(Ken Thompson) |
1972年 | |
当前版本 | |
型態系統 | 静态, 弱类型, 明示, 名称 |
操作系统 | 跨平台 |
網站 | |
主要實作產品 | |
Clang、GCC、MSVC、Turbo C、Watcom C | |
啟發語言 | |
B(BCPL、CPL)、ALGOL 68[3]、組合語言、PL/I、FORTRAN | |
影響語言 | |
大量, 如:awk、BitC、csh、C++、C#、 D、Java、JavaScript、Objective-C、Perl、PHP、Rust等 | |
|
C语言于1969年至1973年間,為了移植與開發UNIX作業系統,由丹尼斯·里奇與肯·汤普逊,以B语言为基础,在贝尔实验室設計、开发出來。二十世纪八十年代,C语言应用日渐广泛。為了避免各開發廠商用的C語言的語法產生差異,美國國家標準局為C語言訂定了一套完整的國際標準語法,稱為ANSI C,作為C語言的標準。与此同时,国际标准化组织也接受该标准为国际标准。因此,ANSI C也同时被称为ISO C。二十世纪八十年代至今的有关程式開發工具,一般都支持符合ANSI C的語法。
C语言具有高效、灵活、功能丰富、表达力强和較高的可移植性等特点,在程式設計中备受青睐,成为最近25年使用最为广泛的编程语言[4]。目前,C语言編譯器普遍存在於各種不同的操作系统中,例如Microsoft Windows、macOS、Linux、Unix等。C語言的設計影響了众多後來的程式語言,例如C++、Objective-C、Java、C#等。现行的许多软件都是由C语言或者其影响和衍生的编程语言开发出来的。
概述
与ALGOL一族的大多数过程式编程语言类似,C語言是一個有結構化程式設計、具有变量作用域(variable scope)以及遞迴功能的程序式語言。其采用的静态类型系统可以防止无意的程序设计操作。C语言中所有的可执行代码都被包含在子程序(函数)裡。其傳遞參數均是以值傳遞(pass by value)[5],另外也可以傳遞指针(a pointer passed by value)。C语言是自由形式语言,即其源代码的缩进并不影响程序的功能,而是使用分号作为语句的结尾,花括号来表示代码块。
由于C语言的语言规模较小,若干高层的机制需要使用定义的函数来提供。比如,C语言并没有直接处理复合对象(例如字符串、集合、列表、数组等)的操作,也没有对于存储器分配工具和内存回收工具的直接定义,同时也本身不具有输入和输出以及文件访问的方法。然而,用户定义的函数和C语言标准库中的函数为这些高层的机制提供了可能性。[6]
C语言也具有以下的特性:[6]
歷史
20世纪70年代,肯·汤姆森为了使其设计的Unix系统更加高效,使用B语言的变种(即C语言)在DEC PDP-7计算机上重写了Unix。C语言中许多重要概念来源于BCPL语言,其对C语言的影响也间接地来源于B语言。在1978年,丹尼斯·里奇和布萊恩·柯林漢合作出版了《C程序设计语言》第一版,事实上即为K&R C标准[7]。1983年,为了制定一个独立于具体机器且无歧义的C语言标准,美国国家标准协会成立了一个委员会,并在1988年完成了该标准的制定,即ANSI C。此标准同时被国际标准化组织所采纳,也被称作ISO C。
其后,C语言至今经历了几次标准更新,诞生了C99、C11和目前最新的标准C18。C语言标准的下一次更新C2x目前正在起草中。
語法
C語言的语法相对简洁而直接。C语言的形式文法由国际标准化组织所制定。[8]簡單來說,C語言包括如下文法:
- 作为一种指令式编程语言,C语言使用语句执行操作。最常见的语句是表达式语句,由一个表达式后加一个分号组成,可以令系统调用函数和为变量赋值;
- 註釋: C语言支持单行注释(以
//
开头)和多行注释(以/*
开始,以*/
结束); - 数据类型: 基本的数据类型包括整数(
int
)、浮点数(float
和double
)、字符(char
)、枚舉enum
等; - 数组: 数组是一组相同类型的数据元素的集合。使用以下方法初始化一個五個元素的整數數組:
int numbers[5] = {1, 2, 3, 4, 5};
- 封裝結構:结构(
struct
)、联合(union
); - 結構化編程和控制结构: C语言包括条件语句(
if
、else
)、循环语句(for
、while
、do-while
)等; - 跳轉語句:C語言允許使用跳轉關鍵字
goto
、break
和continue
來實現程序塊之間的跳轉,這和匯編語言的jmp
關鍵字有一定相似處; - 函数: C语言中的函数是程序的基本模块,可以自定义函数并在程序中调用;
- 靈活且靠近底層的內存控制機制:C程序員可以自由選擇分配何種內存,以及分配多大的內存,如如下代碼所示:
int *array = (int *)malloc(5 * sizeof(int)); // 分配一個包含五個整數的數組 free(array); // 釋放使用malloc分配的內存
Hello World 程序
现在广泛被编程初学者使用的"hello, world"程序实例最初就是出现在《C程序设计语言》第一版中。下面是一個在標準輸出設備(stdout)上打印出 "Hello, world!" 字串的簡單程式。類似的程式,通常作為初學程式語言時的第一個程式:
#include <stdio.h>
int main(void) {
printf("Hello, world!\n");
return 0;
}
其中只有int,void,return为C语言的关键字,预处理器会将#include <stdio.h>
替换为stdio.h文件的内容。
main函数是C语言程序的入口点。
"Hello, world!\n"
中的\n
是一个转义字符,形式为\
加上一个字符。所起的作用在ASCII码中规定。
printf是声明于stdio.h的函数,关于printf的更多细节,参见printf;
关于格式化字符串的更多信息,参见格式化字符串。
内存管理
C语言的特色之一是:程序员必须亲自处理内存的分配细节。语言不负责内存边界检查,这是因为在运行时进行内存边界检查会造成性能问题,与UNIX哲学不符。此特性容易导致缓冲区溢出问题。然而,部分编译器(如英特尔编译器)会出于安全性的考量,提供方法以进行运行时内存边界检查[9]。
大多数C语言实现使用栈(Stack)来保存函数返回地址/栈帧基址、完成函数的参数传递和函数局部变量的存储。然而,在部分极特殊的平台上,使用栈并不能获得最大效率。此时的实现由编译器决定[10]。 如果程序需要在运行的过程中动态分配内存,可以利用堆(Heap)来实现。
基本上C程序的元素存储在内存的时候有3种分配策略:
- 静态分配
如果一个变量声明为全局变量或者是函数的静态变量,这个变量的存储将使用静态分配方式。静态分配的内存一般会被编译器放在数据段或代码段来存储,具体取决于实现。这样做的前提是,在编译时就必须确定变量的大小。 以IA32的x86平台及gcc编译器为例,全局及静态变量放在数据段的低端;全局及静态常量放在代码段的高端。
- 自动分配
函数的自动局部变量应该随着函数的返回会自动释放(失效),这个要求在一般的体系中都是利用栈(Stack)来满足的。相比于静态分配,这时候,就不必绝对要求这个变量在编译时就必须确定变量的大小,运行时才决定也不迟,但是C89仍然要求在编译时就要确定,而C99放松了这个限制。但无论是C89还是C99,都不允许一个已经分配的自动变量运行时改变大小。
所以说C函数永远不应该返回一个局部变量的地址。
要指出的是,自动分配也属于动态分配,甚至可以用alloca函数来像分配堆(Heap)一样进行分配,而且释放是自动的。
- 动态分配
还有一种更加特殊的情况,变量的大小在运行时有可能改变,或者虽然单个变量大小不变,变量的数目却有很大弹性,不能静态分配或者自动分配,这时候可以使用堆(Heap)来满足要求。ANSI C定义的堆操作函数是malloc、calloc、realloc和free。
使用堆(Heap)内存将带来额外的开销和风险。
库
C語言的标准文档要求了一个平台移植C语言的时候至少要实现的一些功能和封装的集合,称为“标准库”,标准庫的声明头部通過预处理器命令#include進行引用。
在C89標準中:
文件 | 简介说明 |
---|---|
<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> | 时间相关 |
在94年的修正版中
- <iso646.h>
- <wchar.h>
- <wctype.h>
在C99中增加了六個函式庫
- <complex.h>
- <fenv.h>
- <inttypes.h>
- <stdbool.h>
- <stdint.h>
- <tgmath.h>
以上是C语言的标准。各个系统各自又对C库函数进行的各种扩充,就浩如烟海了。如POSIX C、GNU C等。
工具軟體
工具軟體可以幫助程式設計者避免一些程式中潛藏或容易出現的問題,例如常會造成程式未預期動作或是執行期錯誤的程式碼。
許多語言都有自動源代碼檢查及審計工具,C語言也有類似工具,像是Lint。可以在程式剛寫好時用Lint找出可能有問題的程式,通過Lint後再用C編譯器進行編譯,許多編譯器也可以設定是否要針對一些可能有問題的程式碼提出警告。MISRA C是一套針對嵌入式系統的法則,可主要也是避免一些可能有問題的程式碼。
也有一些編譯器、程式庫或作業系統可以處理一些非標準C語言的功能,例如邊界值檢查、缓存溢出偵測、序列化及自動垃圾回收功能。
使用像Valgrind或IBM Rational Purify等軟體工具,或者連結有特別malloc函式的程式庫,有助於找出一些運行期記憶體使用的問題。
經典錯誤
“void main()”的用法并不是任何标准制定的[11][12]。 C語言标准語法是“int main()”,任何实现都必须支持int main(void) { /* ... */ }
和int main(int argc, char* argv[]) { /* ... */ }
[13]。 在 C++ 標準中,main的標準型態應是int,否则类型是由实现定义的。任何实现都必须支持int main() { /* ... */ }
和int main(int argc, char* argv[]) { /* ... */ }
[14]。
参见
註腳
注解
參考資料
- . 2020年12月13日 [2020年10月24日] (英語).
- (PDF). 2020年12月11日 [2020年12月17日] (英語).
- Ritchie, Dennis M. . January 1993 [2008-01-01]. (原始内容存档于2015-02-03).
The scheme of type composition adopted by C owes considerable debt to Algol 68, although it did not, perhaps, emerge in a form that Algol's adherents would approve of.
- [TIOBE编程社区指数]. 2012 [2012-11-03]. (原始内容存档于2018-12-25) (英语).
- Brian W. Kernighan and Dennis M. Ritchie. . Prentice-Hall. 1988. ISBN 0-13-110362-8 (英语).
In C, all function arguments are passed ``by value.
- Dennis M. Ritchie,Brian W. Kernighan. . 北京: 机械工业出版社. 2004年1月 [2020-06-10]. ISBN 9787111128069 (中文).
- Stephen Prata. . 北京: 人民邮电出版社. 2005年2月: 3-4 [2020-07-15]. ISBN 9787115130228 (中文).
- . [2022-04-02]. (原始内容存档于2018-02-12) (英语).
- . Intel. [2021-06-01]. (原始内容存档于2021-02-15) (英语).
- (PDF). [2020-06-10]. (原始内容存档 (PDF)于2020-07-22).
- Can I write "void main()"? (页面存档备份,存于)The definition
void main() { /* ... */ }
is not and never has been C++, nor has it even been C. - . [2011-01-21]. (原始内容存档于2011-08-12).
- 「The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):int main(int argc, char *argv[]) { /* ... */ }
or equivalent; or in some other implementation-defined manner.」,引自ISO/IEC 9899:1999, Section 5.1.2.2.1 Program startup - 「An implementation shall not predefine the main function. This function shall not be overloaded. It shall have a return type of type int, but otherwise its type is implementation-defined. All implementations shall allow both of the following definitions of main:
int main() { /* ... */ }
andint main(int argc, char* argv[]) { /* ... */ }
.」,引自 ISO/IEC 14882, 第一版(1998)、第二版(2003)與第三版(2011), section 3.6.1 Main function
參考資料
- Brian Kernighan, Dennis Ritchie: The C Programming Language. 亦被称作K&R,第一部介绍C语言的书籍。
- 第一版, Prentice Hall 1978; ISBN 978-0-13-110163-0. ANSI/ISO标准化之前的C。
- 第二版, Prentice Hall 1988; ISBN 978-0-13-110362-7. ANSI/ISO C。
- 中译本第二版,机械工业出版社 2004; ISBN 978-7-11-112806-9。
- ISO/IEC 9899. The official C:1999 standard, along with technical corrigenda and a rationale. As of 2005 the latest version is ISO/IEC 9899:TC2.
- Samuel P. Harbison, Guy L. Steele: C: A Reference Manual. This book is excellent as a definitive reference manual, and for those working on C compilers. The book contains a BNF grammar for C.
- 4th, Prentice Hall 1994; ISBN 978-0-13-326224-7.
- 5th, Prentice Hall 2002; ISBN 978-0-13-089592-9.
- Derek M. Jones: The New C Standard: A Cultural and Economic Commentary, Addison-Wesley, ISBN 978-0-201-70917-9, online material
- Robert Sedgewick: Algorithms in C, Addison-Wesley, ISBN 978-0-201-31452-6 (Part 1–4) and ISBN 978-0-201-31663-6 (Part 5)
- William H. Press, Saul A. Teukolsky, William T. Vetterling, Brian P. Flannery: Numerical Recipes in C (The Art of Scientific Computing), ISBN 978-0-521-43108-8
外部連結
维基共享资源中相关的多媒体资源:C语言 |
- Coding Programmer Page / C Library Reference and Examples(页面存档备份,存于) (english)
- GCC 首页(页面存档备份,存于)
- GLIBC2 首页(页面存档备份,存于)
- Visual Studio Express 首頁(页面存档备份,存于)
- ISO/IEC 9899(页面存档备份,存于)。C99标准的官方网站。目前(2020年)可直接下载的标准文本是 ISO/IEC 9899:202x(页面存档备份,存于)。