维基百科,自由的百科全书
跳转到:
导航、
搜索
跳过字词转换说明
汉漢
▼
▲
为了阅读方便,本文使用
如果您想对我们的字词转换系统提出一些改进建议,或者提交应用面更广的转换(中文维基百科全站乃至MediaWiki软件),或者报告转换系统的错误,请前往Wikipedia:字词转换请求或候选发表您的意见。
C语言是由UNIX的研制者丹尼斯·里奇(Dennis Ritchie)于1970年 由 肯·汤普逊(Ken Thompson)所研制出的B语言的基础上发展和完善起来的。目前,C语言编译器普遍存在于各种不同的操作系统中,例如UNIX、MS-DOS、Microsoft Windows及Linux等。C语言的设计影响了许多后来的编程语言,例如C++、Objective-C、Java、C#等。
后来于1980年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局(American National Standard Institution)为C语言订定了一套完整的国际标准语法,称为ANSI C,作为C语言的标准。1980年代至今的有关程序开发工具,一般都支持符合ANSI C的语法。
C语言是一个程序语言,设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。C语言也很适合搭配汇编语言来使用。尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台。
C语言最早是由丹尼斯·里奇为了在PDP-11电脑上运行的UNIX系统所设计出来的编程语言,第一次发展在1969年到1973年之间。之所以被称为“C”是因为C语言的很多特性是由一种更早的被称为B语言的编程语言中发展而来。早期操作系统的核心大多由汇编语言组成,随着C语言的发展,C语言已经可以用来编写操作系统的核心。1973年,Unix操作系统的核心正式用C语言改写,这是C语言第一次应用在操作系统的核心编写上。
1978年,丹尼斯·里奇(Dennis Ritchie)和布莱恩·柯林汉(Brian Kernighan)合作出版了《C程序设计语言》的第一版。书中介绍的C语言标准也被C语言程序员称作“K&R C”,第二版的书中也包含了一些ANSI C的标准。K&R C主要介绍了以下特色:
1989年,C语言被 ANSI 标准化(ANSI X3.159-1989)。标准化的一个目的是扩展K&R C。这个标准包括了一些新特性。在K&R出版后,一些新特性被非官方地加到C语言中。
在ANSI标准化自己的过程中,一些新的特性被加了进去。ANSI也规定了一套标准函数库。ANSI ISO(国际标准化组织)成立 ISO/IEC JTC1/SC22/WG14 工作组,来规定国际标准的C语言。通过对ANSI标准的少量修改,最终通过了 ISO 9899:1990。随后,ISO标准被 ANSI 采纳。
在ANSI的标准确立后,C语言的规范在一段时间内没有大的变动,然而C++在自己的标准化创建过程中继续发展壮大。《标准修正案一》在1994年为C语言创建了一个新标准,但是只修正了一些C89标准中的细节和增加更多更广的国际字符集支持。不过,这个标准引出了1999年ISO 9899:1999的发表。它通常被称为C99。C99被ANSI于2000年3月采用。
int main
(
void
)
{
printf
(
"Hello, world!\n"
)
;
return
0
;
}
[编辑] 进一步了解
C语言由函数和变量组成。C的函数就像是Fortran中的子程序和函数。
在C语言中,程序从main开始执行。main函数通过调用和控制其他函数进行工作。例如上面的printf。程序员可以自己写函数,或从库中调用函数。在上面的return 0;使得main返回一个值给调用程序的外壳,表明程序已经成功运行。
一个C语言的函数由返回值、函数名、参数列表(或void表示没有返回值)和函数体组成。函数体的语法和其它的复合的语句部分是一样的。
[编辑] 复合语句
C语言中的复合语句(或称语句块)的格式为:
{
语句
;
语句
;
/* ... */
}
复合语句可以使得几个语句从文法上变成一个语句。
有时必须使用复合语句,否则会产生错误。例如,在运用循环语句的时候,如果循环体(即循环中执行部分)包含多个语句(以分号隔开),则必须使用花括号将他们合并成一个复合语句。如果不这么做,系统仅把第一个分号前的内容看做循环体。
需要注意的是,部分C编译器并不支持在任意位置使用复合语句。
[编辑] 条件语句
C语言有三种条件语句形式。两种是if,另一种是switch。
两种if包括:
if
(表达式
)
语句
;
以及
if
(表达式
)
语句
;
else
语句
;
表达式的值非零表示条件为真;如果条件为假,程序将跳过if处的语句,直接运行if后面的语句。但是如果if后面有else,则当条件为假时,程序跳到else处运行。if和else后面的语句可以是另个if语句,这种套叠式的结构,允许更复杂的逻辑控制流程得以实现。在一般情况下,else一定与最接近的if成对,必要时可用括号{}越过此限制。比较下面两种情况:
if
(表达式
)
if
(表达式
)
语句
;
else
语句
;
if
(表达式
)
{
if
(表达式
)
语句
;
}
else
语句
;
switch通常用于对几种有明确值的条件进行控制。它要求的条件值通常是整数或字符。与switch搭配的条件转移是case。使用case后面的标值,控制程序将跳到满足条件的case处一直往下运行,直到语句退出或遇到break。通常可以使用default把其他例外的情况包含进去。如果switch语句中的条件不成立,控制程序将跳到default处运行;如果省略default子句,则直接运行下一语句。switch是可以嵌套的。
switch
(表达式
)
{
case 值
1
:
语句
;
break
;
case 值
2
:
语句
;
default
:
语句
;
}
[编辑] 循环语句(循环)
C语言有三种形式的循环语句:
do
语句
while
(表达式
)
;
while
(表达式
)
语句
;
for
(表达式
1
; 表达式
2
; 表达式
3
)
语句
;
在while和do中,语句将运行到表达式的值为零时结束。在do...while语句中,循环将至少被运行一次。这三种循环结构可以互相转化:
for
(
<表达式
1
>;
<表达式
2
>;
<表达式
3
>
)
<语句
>;
如果<语句>中不使用continue语句的话,相当于
<表达式
1
>;
while
(
<表达式
2
>
)
{
<语句
>;
<表达式
3
>;
}
当循环条件一直为真时,将产生死循环。
[编辑] 跳转语句
跳转语句包括四种:goto,continue,break和return。
goto语句是无条件转移语句:
goto 标记;
标记必须在当前函数中定义,使用“标记:”的格式定义。程序将跳到标记处继续运行。由于goto容易产生阅读上的困难,所以应该尽量少用。
continue语句用在循环语句中,作用是退出当前一轮的循环,马上开始下一轮循环。
break语句用在循环语句或switch中,作用是退出当前循环,跳到循环体外继续运行。但是使用break只能跳出一层循环。在要跳出多重循环时,可以使用goto使得程序更为简洁。
当一个函数运行退出后要返回一个值时,使用return。return可以跟一个表达式或变量。如果return后面没有值,将运行不返回值。
[编辑] 在C语言中的运算符号
()、 []、 -> 、 .、!、 ++、 -- | 圆括号、方括号、指针、成员、逻辑非、自加、自减 |
++ 、 -- 、 * 、 & 、 ~ 、! 、 + 、 - 、 sizeof、(cast) | 单目运算符 |
* 、 / 、% | 算术运算符 |
+ 、 - | 算术运算符 |
<< 、 >> | 位运算符 |
< 、 <= 、 > 、 >= | 关系运算符 |
== 、!= | 关系运算符号 |
& | 位与 |
^ | 位异或 |
| | 位或 |
&& | 逻辑与 |
|| | 逻辑或 |
? 、: | 条件运算符 |
= 、 += 、 -= 、 *= 、 /= 、%= 、 &= 、 |= 、 ^= | 赋值运算符 |
, | 顺序运算符 |
比较特别的是,比特右移(>>)运算符可以是算术(左端补最高有效位)或是逻辑(左端补 0)位移。例如,将 11100011 右移 3 比特,算术右移后成为 11111100,逻辑右移则为 00011100。因算术比特右移较适于处理带负号整数,所以几乎所有的编译器都是算术比特右移。[2]
运算符的优先级从高到低大致是:单目运算符、算术运算符、关系运算符、逻辑运算符、条件运算符、赋值运算符(=)和逗号运算符。
[编辑] 数据类型
[编辑] 基础数据类型
注意:以下是典型的数据位长和范围。但是编译器可能使用不同的数据位长和范围。这取决于使用的编译器。请参考具体的参考手册。
在头文件和中说明了基础数据的长度。float,double和long double的范围就是在IEEE 754标准中提及的典型数据。
关键字 | 位长(字节) | 范围 | 格式化字符串 |
---|
char | 1 | -128..127(或0..255,与体系结构相关) | %c |
unsigned char | 1 | 0..255 | |
signed char | 1 | -128..127 | |
int | 2(16位系统) 或 4 | -32768..32767 或 -2147483648..2147483647 | %i,%d |
unsigned int | 2 或 4 | 0..65535 或 0..4294967295 | %u |
signed int | 2 或 4 | -32768..32767 或 -2147483648..2147483647 | %i,%d |
short int | 2 | -32768..32767 | %hi |
unsigned short | 2 | 0..65535 | %hu |
signed short | 2 | -32768..32767 | |
long int | 4 或 8[3] | -2147483648..2147483647 或 -9223372036854775808..9223372036854775807 | %li,%ld |
unsigned long | 4 或 8 | 0..4294967295 或 0..18446744073709551615 | %lu |
signed long | 4 或 8 | -2147483648..2147483647 或 -9223372036854775808..9223372036854775807 | |
long long | 8 | -9223372036854775808..9223372036854775807 | %lli |
unsigned long long | 8 | 0..18446744073709551615 | %llu |
float | 4 | 3.4x10−38..3.4x10+38 (7 sf) | %f,%e,%g |
double | 8 | 1.7x10−308..1.7x10+308 (15 sf) | %f,%e,%g |
long double | 8 或以上 | 编译器相关 | %Lf,%Le,%Lg |
[编辑] 数组
如果一个变量名后面跟着一个有数字的中括号,这个声明就是数组声明。字符串也是一种数组。它们以ASCII的NUL作为数组的退出。要特别注意的是,方括内的索引值是从0算起的。
例如:
int myvector
[
100
];
/* 从myvector[0]至myvector[99]止共100个元素 */
char mystring
[
80
];
float mymatrix
[
3
]
[
2
]
=
{
2.0
,
10.0
,
20.0
,
123.0
,
1.0
,
1.0
}
;
int notfull
[
3
]
[
3
]
=
{
{
1
}
,
{
1
,
2
,
3
}
,
{
4
,
5
}
}
;
(
*
)
char lexicon
[
10000
]
[
300
];
/* 共一万个最大长度为300的字符数组。*/
int a
[
3
]
[
4
];
上面最后一个例子创建了一个数组,但也可以把它看成是一个多维数组。注意数组的下标从0开始。这个数组的结构如下:
a[0][0] | a[0][1] | a[0][2] | a[0][3] |
a[1][0] | a[1][1] | a[1][2] | a[1][3] |
a[2][0] | a[2][1] | a[2][2] | a[2][3] |
例子(*)创建了一个3*3的二维数组,初始化时有些元素并未赋值。如下:
-
1 0 0
-
1 2 3
-
4 5 0
为0的位置的数值是随机的。
[编辑] 指针
如果一个变量声明时在前面使用 * 号,表明这是个指针型变量。换句话说,该变量存储一个地址,而 *(此处特指单目运算符 * ,下同。C语言中另有 双目运算符 * ) 则是取内容操作符,意思是取这个内存地址里存储的内容。指针是 C 语言区别于其他同时代高级语言的主要特征之一。
指针不仅可以是变量的地址,还可以是数组、数组元素、函数的地址。通过指针作为形式参数可以在函数的调用过程得到一个以上的返回值(不同于return(z)这样的仅能得到一个返回值。
指针是一把双刃剑,许多操作可以通过指针自然的表达,但是不正确的或者过分的使用指针又会给程序带来大量潜在的错误。
例如:
int
* pi
;
/* 指向整型数据的指针变量 */
int
* api
[
3
];
/* 由指向整型数据的指针构成的数组,长度为 3 */
char
** argv
;
/* 指向一个字符指针的指针 */
struct
{
int member
;
} stinst
,
* pst
=
& stinst
;
/* pst是一个指向一个匿名结构体的指针 */
储存在指针中的地址所指向的数值在程序中可以由 * 读取。例如,在第一个例子中, *pi 是一个整型数据。这叫做引用一个指针。
另一个运算符 &,叫做取地址运算符,它将返回一个变量、数组或函数的存储地址。因此,下面的例子:
int i
,
*pi
;
/* int and pointer to int */
pi
=
&i
;
i 和 *pi 在程序中可以相互替换使用,直到 pi 被改变成指向另一个变量的地址。
当指针指向结构体时,可以使用运算符 -> 代替 *和. 的作用,如以下两个表达式为等效:
(
*pst
).
member
pst
->member
[编辑] 字符串
C语言的字符串其实就是char型数组,所以使用字符串并不需要引用库。但是C标准库确实包含了一些用于对字符串进行操作的函数,使得它们看起来就像字符串而不是数组。使用这些函数需要引用头文件。
[编辑] 文件输入/输出
在C语言中,输入和输出是经由标准库中的一组函数来实现的。在ANSI/ISO C中,这些函数被定义在头文件中。
[编辑] 标准输入/输出
有三个标准输入/输出是标准I/O库预先定义的:
- stdin 标准输入
- stdout 标准输出
- stderr 输入输出错误
下面的这个例子显示了一个过滤程序(filter program)是怎样构成的。
# include
int main
(
int argc
,
const
char
* argv
[
]
)
{
int c
;
while
(
1
)
{
c
=
getchar
(
)
;
if
(c
==EOF
)
{
perror
(
"getchar()"
)
;
return
-
1
;
}
putchar
(c
)
;
}
return
0
;
}
[编辑] 函数
C语言的基本结构单位是函数。系统首先调用main函数(主函数),通过函数的嵌套调用,再调用其他函数。函数可以是系统自带的函数,也可以是用户定义的函数。C语言中,不允许函数的嵌套声明。
[编辑] 内存管理
C语言的特色之一是:程序员必须亲自处理内存的分配细节。
C语言使用栈(Stack)来保存函数返回地址/栈祯基址、完成函数的参数传递和函数局部变量的存储。 如果程序需要在运行的过程中动态分配内存,可以利用堆(Heap)来实现。
基本上C程序的元素存储在内存的时候有3种分配策略:
如果一个变量声明为全局变量或者是函数的静态变量,这个变量的存储将使用静态分配方式。静态分配的内存一般会被编译器放在数据段或代码段来存储,具体取决于实现。这样做的前提是,在编译时就必须确定变量的大小。 以IA32的x86平台及gcc编译器为例,全局及静态变量放在数据段的低端;全局及静态常量放在代码段的高端。
函数的自动局部变量应该随着函数的返回会自动释放(失效),这个要求在一般的体系中都是利用栈(Stack)来满足的。相比于静态分配,这时候,就不必绝对要求这个变量在编译时就必须确定变量的大小,运行时才决定也不迟,但是C89仍然要求在编译时就要确定,而C99放松了这个限制。但无论是C89还是C99,都不允许一个已经分配的自动变量运行时改变大小。
所以说C函数永远不应该返回一个局部变量的地址。
要指出的是,自动分配也属于动态分配,甚至可以用alloca函数来像分配堆(Heap)一样进行分配,而且释放是自动的。
还有一种更加特殊的情况,变量的大小在运行时有可能改变,或者虽然单个变量大小不变,变量的数目却有很大弹性,不能静态分配或者自动分配,这时候可以使用堆(Heap)来满足要求。ANSI C定义的堆操作函数是malloc、calloc、realloc和free。
使用堆(Heap)内存将带来额外的开销和风险。
[编辑] 安全问题
C语言的特色之一是:语言不负责内存边界检查。
[编辑] 库
-
主条目:
C_标准库
C语言的标准文文件要求了一个平台移植C语言的时候至少要实现的一些功能和封装的集合,称为“标准库”,标准库的声明头部通过预处理器命令#include进行引用。
在C89标准中:
文件 | 简介说明 |
---|
| 断言相关 |
| 字符类型判断 |
| 标准报错机制 |
| 浮点运算 |
| 各种体系结构限制 |
| 本地化接口 |
| 数学函数 |
| 跨函数跳转 |
| 信号(类似UNIX的信号定义,但是差很远) |
| 可变参处理 |
| 一些标准宏定义 |
| 标准I/O库 |
| 标准工具库函数 |
| ASCIIZ字符串及任意内存处理函数 |
| 时间相关 |
在94年的修正版中
在C99中增加了六个库
以上是C语言的标准,而各个平台各自又对C库函数进行的各种扩充,就浩如烟海了。如POSIX C、GNU C等。
[编辑] 工具软件
工具软件可以帮助程序设计者避免一些程序中潜藏或容易出现的问题,例如常会造成程序未预期动作或是运行期错误的代码。
许多语言都有自动源代码检查及审计工具,C语言也有类似工具,像是Lint(英语:lint programming tool)。可以在程序刚写好时用Lint找出可能有问题的程序,通过Lint后再用C编译器进行编译,许多编译器也可以设置是否要针对一些可能有问题的代码提出警告。MISRA C是一套针对嵌入式系统的法则,可主要也是避免一些可能有问题的代码。
也有一些编译器、程序库或操作系统可以处理一些非标准C语言的功能,例如边界值检查、缓存溢出侦测、串行化及自动垃圾回收功能。
使用像Valgrind或IBM Rational Purify(英语:Purify)等软件工具,或者连结有特别malloc函数的程序库,有助于找出一些运行期存储器使用的问题。
[编辑] 保留关键字
char | short | int | unsigned |
long | float | double | struct |
union | void | enum | signed |
const | volatile | typedef | auto |
register | static | extern | break |
case | continue | default | do |
else | for | goto | if |
return | switch | while | sizeof |
[编辑] C99新增关键字
_Bool | _Complex | _Imaginary | inline | restrict |
[编辑] 经典错误
void main的用法并不是任何标准制定的[4][5],是Microsoft制定的。 C语言正确的语法是int main[6]。 在 C++ 标准中,虽然 main 的标准型态应是 int,但编译器实现中也可以自行定义型态,不过,所有实现均应接受 int main 的用法[7]。
[编辑] C//
C// 是一种结构化的并行语言,读作C parallel。它基于标准C语言但扩展了为数不多的构造用来表示并行性和进程交互。C// 的核心是称为一致区域的构造,它方便了结构化的、确定的、终止的和复合的并行程序的开发。[来源请求]
[编辑] 参考文献
- ^ GCC从3.0版本开始正式支持C99(-std=c99)
- ^ 经测试,gcc4.4.3使用C99标准的结果依然是00011100,即逻辑移位。
- ^ GCC、Clang等实现中,64位代码的long类型为64位,而MSVC中则维持32位
- ^ Bjarne Stroustrup's C++ Style and Technique FAQ (Modified October 4, 2009) - Can I write "void main()"?
- ^ 用 C99 进行开放源代码的开发
- ^ ISO/IEC 9899-1999, Section 5.1.2.2.1 Program startup
- ^ “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: ...(下略)”,引自 ISO/IEC 14882, 第一版(1998)与第二版(2003), section 3.6.1 Main function
- Brian Kernighan, Dennis Ritchie: The C Programming Language. Also known as K&R — The original book on C.
- 1st, Prentice Hall 1978; ISBN 0-13-110163-3. Pre-ANSI C.
- 2nd, Prentice Hall 1988; ISBN 0-13-110362-8. ANSI C.
- 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 0-13-326224-3.
- 5th, Prentice Hall 2002; ISBN 0-13-089592-X.
- Derek M. Jones: The New C Standard: A Cultural and Economic Commentary, Addison-Wesley, ISBN 0-201-70917-1, online material
- Robert Sedgewick: Algorithms in C, Addison-Wesley, ISBN 0-201-31452-5 (Part 1–4) and ISBN 0-201-31663-3 (Part 5)
- William H. Press, Saul A. Teukolsky, William T. Vetterling, Brian P. Flannery: Numerical Recipes in C (The Art of Scientific Computing), ISBN 0-521-43108-5
[编辑] 外部链接
- GCC 首页
- GLIBC2 首页
- C 语言学习笔记
- 美丽 C 世界(C语言教学讲义)
- Linux C编程一站式学习
- Linux C/C++编程一站式学习
- C 语言教材
- Full guide for ANSI standard C programming language.
- C Programming Course
- C Programming Notes
- C Standard Library
- (英文)Visual Studio Express 首页
- (英文)Visual Studio Express 下载页面
- (正体中文)Visual Studio Express 首页
- (正体中文)Visual Studio Express Visual C++ 下载页面
- ISO/IEC 9899。C99标准的官方网站。目前(2009年)可直接下载的标准文本是 ISO/IEC 9899:201x。
- C语言入门学习
[编辑] 参见