文章目录
- 1. C 语言起源
- 2. C 语言标准
- 2.1 K&R C 标准
- 2.2 ANSI/ISO C 标准
- 2.3 C99 标准
- 2.4 C11 标准
- 3. 编程机制
- 3.1 目标代码文件、可执行文件和库
- 3.2 Linux 系统
- 4. C 程序示例
- 4.1 #include 指令和头文件
- 4.2 main 函数
- 4.3 注释
- 4.4 花括号、函数体和块
- 4.5 声明
- 4.6 赋值
- 4.7 printf() 函数
- 4.8 return 语句
- 5. 关键字和保留标识符
- 6. 基本数据类型
- 6.1 基本类型关键字
- 6.2 整数类型
- 6.2 浮点类型
- 6.3 类型大小
1. C 语言起源
1972 年,贝尔实验室的 丹尼斯·里奇(Dennis Ritch)和 肯·汤姆逊(Ken Thompson)在研究 Unix 操作系统时设计了 C 语言。C 语言是在 B 语言(汤姆逊发明)的基础上进行设计的。
2. C 语言标准
2.1 K&R C 标准
1978 年,布莱恩·柯林汉(Brain Kernighan)和丹尼斯·里奇(Dennis Ritch)合著的 The C Programming Language (《C 语言程序设计》)第一版是公认的 C 标准,通常称之为 K&R C 或经典 C。
2.2 ANSI/ISO C 标准
美国国家标准协会(ANSI)于 1983 年组建一个委员会开发了一套新标准,并于 1989 年正式公布。该标准(ANSI C)定义了 C 语言和 C 标准库。国际标准化组织(ISO)于 1990 年采用了这套 C 标准(ISO C)。所以两者是完全相同的标准。ANSI/ISO 标准通常也叫作 C89 或 C90。
2.3 C99 标准
1994 年,ANSI/ISO 联合委员会开始修订 C 标准,最终在 1999 年发布了 C99 标准。(并不是所有的编译器都支持 C99)
2.4 C11 标准
2011 年标准委员会发布了 C11 标准。(C99 的一些特性成为 C11 的可选项)
3. 编程机制
用 C 语言编写程序时,编写的内容被存储在文本文件中,该文件被称为源代码文件(source code file),该文件以 .c 结尾(如:hello.c)。在文件名中,点号(.)前面的部分称为基本名(basename),点号后面的部分称为扩展名(extension)。
3.1 目标代码文件、可执行文件和库
C 语言编程的基本策略是,用程序将源代码文件转换成可执行文件。典型的 C 实现通过编译和链接两个步骤来完成这一过程。编译器将源代码转换成中间代码,链接器将中间代码和其他代码合并,生成可执行文件。
中间文件有很多种形式,其中最普遍的是把源代码转换成机器语言代码,并把结果放在目标代码文件中(简称目标文件或目标代码)。虽然目标文件中含有机器语言代码,但是并不能直接运行该文件,因为首先目标文件中缺少启动代码(startup code),启动代码充当着程序和操作系统之间的接口;其次,目标文件还缺少库函数,几乎所有的 C 程序都要使用 C 标准库中的函数。
链接器在作用是,把目标代码、系统的标准启动代码和库代码这 3 部分合并成一个文件,即可执行文件。对于库代码,链接器只会把程序中要用到的库函数代码提取出来。
3.2 Linux 系统
Linux 系统中要编写运行 C 程序,需要使用 GNU 提供的 GCC 公用域 C 编译器。如果 Linux 之前没有安装 GCC,则需要输入以下命令安装GCC。
yum install gcc
gcc 指令基本语法如下:
gcc -o 可执行文件名 源代码文件
例子:在 Linux 系统中编写一个 C 程序。
- 创建 hello.c 文件
vim hello.c
- 在 hello.c 中编写源代码并保存
#include <stdio.h>
int main(void)
{
printf("hello world!\n");
return 0;
}
- 编译
gcc -o hello.out hello.c
- 运行可执行文件
./hello.out
4. C 程序示例
#include <stdio.h>
void hello(void); /*ANSI/ISO C 函数原型*/
int main(void)
{
int num; /*声明(定义)一个名为num的变量*/
num = 1; /*为num赋一个值1*/
printf("hello world!\n"); // 使用printf函数,打印“hello world!”
hello();
return 0;
}
void hello(void) // 函数定义的开始
{
printf("hello C!");
}
4.1 #include 指令和头文件
#include 这行代码是一条 C 预处理器指令。通常,C 编译器在编译前会对源代码做一些准备工作,即预处理。所有的 C 编译器都提供 stdio.h 文件。该文件名的含义是标准输入/输出头文件。该文件包含了供编译器使用的输入和输出函数(printf 函数)信息。通常,在 C 程序顶部的信息集合被称为 头文件(header)。
头文件包含了编译器创建最终可执行程序要用到的信息。例如,头文件中可以定义一些常量,或者指明函数名以及如何使用它们。但是,函数的实际代码在一个预编译代码的库文件中。
4.2 main 函数
C 程序一定从 main() 函数开始执行(目前不需要考虑额外情况)。除了 main() 函数,我们还可以任意命名其他函数,但是 main() 函数必须是开始函数。圆括号用于识别这是一个函数。
int 是 main() 函数的返回类型,代表返回的值是整数。这里的返回值返回给了操作系统。
通常,函数名后面的圆括号中包含了一些传入函数的信息。该例中没有传递任何信息,因此圆括号内是单词 void。
如果浏览旧式的 C 代码,可能会发现程序以如下形式开始:main()。C90 勉强接受这种形式,但是 C99 和 C11 标准不允许这样写。此外,我们还可以看到这样的形式:void main()。一些编译器允许这样写,但是所有的标准中都未认可这种写法。所以这种写法不推荐使用。
4.3 注释
在程序中,被 /* */ 两个符号括起来的部分是程序的注释。较长的注释可单独放一行或者多行,在 /* 和 */ 之间的内容都会被编译器忽略。C99 新增了另一种风格的注释,普遍用于 C++ 和 Java。这种风格使用 // 符号创建注释,但仅限于单行。
4.4 花括号、函数体和块
在上面的程序中,花括号 { } 把 main 函数括起来。一般而言,所有的 C 函数都使用花括号标记函数体的开始和结束。这是规定,不能省略。花括号还可以把函数中的多条语句合并为一个单元或块。
4.5 声明
声明是 C 语言最重要的特性之一。在该例中,声明完成了两件事,第一,在程序中有一个名为 num 的变量(variable)。第二,int 表名 num 是一个整数。int 是一种数据类型。编译器使用这些信息为 num 变量在内存中分配存储空间。
int 是 C语言的一个 关键字,表示一种基本的 C 语言数据类型。关键字是语言定义的单词,不能做其他用途,比如,不能用关键字作为函数名或者变量名。示例中 num 是一个 标志符(identifier),也就是一个变量、函数或者其他实体的名称。因此, 声明把特定标志符与计算机内存中的特定位置联系起来,同时也确定了储存在某位置的信息类型或者数据类型。
标志符的命名规则:由字母、数字和下划线构成,数字不能作为第一个字符。
在 C 语言中,所有的变量必须先声明才能使用。这意味着必须列出程序中用到的所有变量名及其类型。以前的 C 语言,还要求把变量的声明放在块的顶部,其他语句不能在任何声明前面。但是 C99 和 C11 遵循 C++ 的惯例,可以把声明放在块中的任何位置。尽管如此,首次使用变量之前一定要先声明它。
当一行中声明两个或多个变量时,变量之间用逗号分隔。
hello() 函数在程序中出现了三次,第 1 次是函数原型(prototype),告知编译器在程序中要使用该函数;第 2 次是以函数调用的形式出现在 main() 函数中;最后一次出现在函数定义中,函数定义即函数本身的源代码。
C90 标准新增了函数原型,函数原型是一种声明形式,告知编译器正在使用某函数,因此函数声明也被称作函数声明。函数原型还指明了函数的属性,比如函数的返回值类型,参数。C 标准建议,要为程序中所有的函数提供函数原型。早期的 C 语言支持一种更简单的函数声明,只需指定返回类型,不用描述参数。C90、C99 和 C11标准都承认旧版本的形式,但是也表明会逐渐淘汰这种过时的写法。
4.6 赋值
赋值是 C 语言的基本操作之一。num = 1;的意思是 “把值 1 赋给变量 num”。在声明变量时,编译器在计算机内存中为变量 num 预留了空间,然后执行赋值语句时,把值存储在之前的预留位置。可以个给 num 赋不同的值,这就是 num 被称为变量的原因。
赋值表达式语句从右侧把值赋到左侧。
4.7 printf() 函数
printf() 函数是 C 语言的一个标准函数。圆括号中内容是从 main() 函数传递给 printf() 函数的信息,该信息称为参数,更确切的说是函数的实际参数(actual argument)。在 C 语言中,实际参数(简称实参)是传递给函数的特定值,形式参数(简称形参) 是函数中用于存储值的变量。
printf() 函数会查看其双引号中的内容,并将其打印在屏幕上。
printf() 函数的双引号中的 \n 代表是一个换行符。换行符是一个 转义序列(escape sequence)。转义序列用于代表难以表示或无法输入的字符。每个转义序列都以反斜杠字符(\)开始。
4.8 return 语句
int main(void) 中 int 表明 main 函数应该返回一个整数。有返回值的 C 函数要有 return 语句,该语句以 return 关键字开始,后面是待返回的值,并以分号结尾。如果遗漏 main() 函数中的 return 语句,程序在运行至最外面的右花括号( })时会返回 0。因此可以省略 main() 函数末尾的 return 语句。但是不要在其他有返回值的函数中遗漏它。
5. 关键字和保留标识符
ISO/ANSI C 标准 32 个关键字:
auto | break | case | char | const | continue | default | do |
double | else | enum | extern | float | for | goto | if |
int | long | register | return | short | signed | sizeof | static |
struct | switch | typeof | union | unsigned | void | volatile | while |
C99 标准新增 5 个关键字:
inline | restrict | _Bool | _Complex | _Imaginary |
C11 标准新增 7 个关键字:
_Alignas | _Alignof | _Atomic | _Static_assert | _Noreturn | _Thread_local | _Generic |
关键字是 C 语言的词汇,不能用它们作为标志符。如果关键字使用不当,编译器会视为语法错误。还有一些保留标志符,C 语言已经指定了它们的用途或保留了它们的使用权,也不能作为标识符。保留标识符包括那些以下划线字符开头的标识符和标准库函数名,如 printf()。
6. 基本数据类型
6.1 基本类型关键字
最初 K&C 的关键字 | C90 标准添加的关键字 | C 90 标准添加的关键字 |
int | signed | _Bool |
long | void | _Complex |
short | _Imaginary | |
unsigned | ||
char | ||
float | ||
double |
其中,int 关键字表示基本的整数类型,long、short、signed 和 unsigned 用于提供基本整数类型的变式。char 关键字用于指定字母和其它字符,也可以表示较小的整数。float、double 和 long double 代表浮点数类型。_Bool 代表布尔类型(true 或 false,1 表示 true,0 表示 false)。_Complex 代表复数,_Imaginary 代表虚数。
6.2 整数类型
有符号整型:
- int
- char
- signed char
- short 或 short int
- long 或 long int
- long long 或 long long int
无符号整型:
- unsigned int
- unsigned char
- unsigned short
- unsigned long
6.2 浮点类型
- float (单精度)
- double (双精度)
- long double
6.3 类型大小
sizeof 是 C 语言的内置运算符,以字节为单位指定类型的大小,C99 和 C1 提供 %zd 转换说明匹配 sizeof 的返回类型。一些不支持 C99 和 C11 的编译器可以用 %u 或 %lu 代替 %zd。
#include <stdio.h>
int main(void)
{
/* C99为类型大小提供%zd转换说明 */
printf("Type int has a size of %zd bytes.\n", sizeof(int));
printf("Type char has a size of %zd bytes.\n", sizeof(char));
printf("Type long has a size of %zd bytes.\n", sizeof(long));
printf("Type long long has a size of %zd bytes.\n", sizeof(long long));
printf("Type double has a size of %zd bytes.\n", sizeof(double));
printf("Type long double has a size of %zd bytes.\n", sizeof(long double));
return 0;
}
注意:C 语言中,各种类型的存储大小与系统的位数有关,但目前通用以 64 位为主。以下列出了 32 位系统和 64 位系统的存储大小差别(windows 相同) :