C 语言入门/C 语言入门程序
这是一个简单的 C 程序,用于计算球体的体积
/* sphere.c */
#include <stdio.h> /* Include header file for printf. */
#define PI 3.141592654f /* Define a constant. */
static float sphere(float); /* Function prototype. sphere is given internal linkage with the keyword
'static' since it isn't used outside of this translation unit. */
int main(void) /* Main function. */
{
float volume; /* Define a float variable. */
float radius = 3; /* Define and initialize variable. */
volume = sphere(radius); /* Call sphere and copy the return value into volume. */
printf( "Volume: %f\n", volume ); /* Print the result. */
return 0;
}
static float sphere(float rad) /* Definition of a volume calculating function. */
{
float result; /* "result" is defined with an automatic storage duration and block scope. */
result = rad * rad * rad;
result = 4 * PI * result / 3;
return result; /* "result" is returned to the function which called sphere. */
}
在这个程序中可以观察到的第一个特点是注释用 "/*" 和 "*/" 括起来。注释几乎可以放在任何地方,因为编译器会忽略它们。另一个明显的特征是程序中的单个语句以 ";" 结束。忘记 ";" 或在不需要的地方添加 ";" 是常见的 C 编程错误。代码行通过使用花括号 ("{ }") 分组为块。
C 语言区分大小写。所有 C 语言关键字都小写。程序变量和函数名称可以使用任何大小写,但按照惯例应使用小写。"常量"(稍后会讨论)按照惯例使用大写。
并非 C 程序中的所有行都是可执行语句。上面显示的一些语句是 "预处理指令"。
C 语言编译是一个多阶段过程。为了创建一个程序,C 语言编译器系统会执行以下步骤
- 它将源文件文本通过 "C 预处理器"。它所做的只是对源文件执行各种文本操作,例如 "宏扩展"、"常量扩展"、"文件包含" 和 "条件编译",这些内容将在后面解释。预处理器的输出是用于实际编译的二级源文件。您可以将 C 预处理器视为一种特殊的自动 "文本编辑器"。
- 接下来,它将二级源文件通过编译器本身,编译器实际上将源代码语句转换为它们的二进制等价物。也就是说,它从源文件创建一个 "目标文件"。
- 但是,目标文件仍然无法执行。如果它使用 C 库函数,例如上面的示例中的 "printf()",则库函数的二进制代码必须与程序目标文件合并或 "链接"。此外,需要将一些寻址信息链接到目标文件,以便它可以在目标系统上加载和运行。
这些链接任务由 "链接器" 执行,链接器将一个或多个目标文件链接到二进制库文件,以创建一个可以实际运行的 "可执行" 文件。
C 语言有大量的库和库函数。C 语言本身只有很少的语句,因此它的许多功能都是通过库调用实现的。
意图用于 C 预处理器而不是 C 编译器本身的命令以 "#" 开头,被称为 "预处理指令" 或 "元命令"。上面的示例程序中有两个这样的元命令
#include <stdio.h>
#define PI 3.14
第一条语句 "#include <stdio.h>" 只是在编译之前将文件 "stdio.h" 的内容合并到当前程序文件中。"stdio.h" 文件包含使用标准 I/O 库所需的声明,该库提供 "printf()" 函数。
顺便说一句,"stdio.h" 文件或 "头文件" 只包含声明。库的实际代码包含在单独的库文件中,这些库文件在链接时添加。如果需要,可以创建使用自定义声明加载的自定义头文件,然后如下包含在程序中
#include "mydefs.h"
尖括号 ("< >") 不用于自定义头文件。它们只用于定义与 C 编译器一起提供的默认头文件(在 Unix/Linux 系统上,这些文件位于目录 "/usr/include" 中)。
C 程序由一个或多个函数组成。上面的程序包含两个用户定义的函数 "main()" 和 "sphere()",以及 "printf()" 库函数。
在编写独立程序时,"main()" 函数是必需的。它定义了程序运行时自动执行的函数。所有其他函数将直接或间接由 "main()" 调用。
C 函数的调用方法是简单地指定它的名称,并在后面的括号中包含任何参数,参数之间用逗号分隔。在上面的程序中,"printf()" 函数的调用方法如下
printf( "Volume: %f\n", volume );
此调用提供了两个参数。第一个—"Volume: %f\n"——提供文本和一些格式化信息。第二个—"volume"——提供一个数值。
函数可以返回也可以不返回值。"sphere()" 函数返回一个值,因此它的调用方法如下
volume = sphere( radius );
函数使用 "return" 关键字返回值。在 "sphere" 的情况下,它使用以下语句返回球体的体积
return result;
C 程序中的所有变量都必须 "声明",方法是指定它们的名称和类型。示例程序为 "main" 例程声明了两个变量
float volume;
float radius = 3;
——以及 "sphere" 例程中的一个变量
float result;
"volume"、"radius" 和 "result" 的声明指定了一个浮点变量。该声明允许在需要时在声明时初始化变量,在本例中,声明 "radius" 并为其赋值 "3"。
所有这三个声明都定义了块级作用域的变量。具有块级作用域的变量只存在于声明它们的块中。可以在不同的块中声明同名的变量,而不会相互干扰。还可以声明具有文件级作用域的变量,这些变量可以由所有函数共享,方法是在翻译单元的所有块之外声明它们。默认情况下,所有具有文件级作用域的标识符都被赋予外部链接。只有使用关键字 "static" 才能将标识符赋予内部链接。像这样的声明
extern int a;
将 "a" 识别为一个 int,其存储在其他地方定义;最好是在另一个翻译单元中。
/* global.c */
#include <stdio.h>
void somefunc( void );
int globalvar;
void main()
{
extern int globalvar;
globalvar = 42;
somefunc();
printf( "%d\n", globalvar );
}
void somefunc( void )
{
extern int globalvar;
printf( "%d\n", globalvar );
globalvar = 13;
}
除了变量声明之外,上面的示例程序还包含函数声明或 "函数原型",它允许 C 编译器对程序中对函数的调用进行检查,并在调用不正确时发出错误
float sphere(float);
函数原型声明函数返回的值的类型(如果它不返回值,则类型将为 "void"),以及要为函数提供的参数。
最后,"printf()" 库函数为程序提供文本输出功能。可以使用 "printf()" 函数打印简单的消息,如下所示
printf( "Hello, world!" );
——显示文本
Hello, world!
请记住,"printf()" 不会自动添加 "换行符",以允许后续 "printf()" 在下一行显示中打印。例如
printf( "Twas bryllig " );
printf( "and the slithy toves" );
——打印文本
Twas bryllig and the slithy toves
必须添加换行符 ("\n") 以强制换行。例如
printf( "Hello,\nworld!" );
——给出
Hello, world!
这些示例只打印预定义的文本常量。可以在字符串中包含 "格式代码",然后在字符串后面加上一个或多个变量,以打印它们包含的值
printf( " Result = %f\n", result );
这将打印类似的内容
Result = 0.5
"%f" 是格式代码,它告诉 "printf" 打印一个浮点数。举另一个例子
printf( "%d times %d = %d\n", a, b, a * b );
——将打印类似的内容
4 times 10 = 40
"%d" 打印一个整型数量。可以在参数列表中包含数学或字符串表达式和函数。
为了简单地打印一段文本,有一个更简单的函数 "puts()",它显示指定的文本并自动追加一个换行符
puts( "Hello, world!" );
仅仅为了好玩,让我们看看在 ANSI 之前的 C 语言版本中,我们的示例程序会是什么样子
/* oldspher.c */
#include <stdio.h>
#define PI 3.141592654
float sphere(); /* Parameters not defined in function prototype. */
main()
{
float volume;
int radius = 3;
volume = sphere( radius );
printf( "Volume: %f\n", volume );
}
float sphere( rad )
int rad; /* Parameter type not specified in function header. */
{
float result;
result = rad * rad * rad;
result = 4 * PI * result / 3;
return result;
}
以下部分详细阐述了本节概述的原理。