目录
2.符号常量(Symbolic Constants 或 Macros):
一 简介
本文将从C语言程序结构、C语言基本语法元素两个方面详细的介绍C语言的基础知识
二 C语言程序结构
B.源代码文件的基本组成(注释、预处理器指令、函数等)
C语言源代码文件的基本组成包括以下几个重要部分:
1.预处理器指令 (#
开头)
#include
:用于包含其他文件(通常是头文件,包含了函数声明和类型定义),例如 #include <stdio.h>
。
#define
:用于定义宏,可以在编译阶段进行文本替换,也可以用于定义常量。
#ifdef
, #ifndef
, #else
, #endif
:条件编译指令,根据宏定义的存在与否来决定哪些代码块参与编译。
#pragma
:用于向编译器发出某种形式的指示,具体的含义取决于编译器。
2.注释
单行注释:以 //
开始,直到行尾的所有内容都被视为注释,例如 // 这是一个单行注释
。
多行注释:以 /*
开始,以 */
结束,中间的内容被视为注释,例如:
/*
* 这是一个
* 多行注释
*/
3.函数定义
C程序通常由一个或多个函数构成,每个函数由函数头部(包括返回类型、函数名和参数列表)和函数体组成。
int main() { // 主函数,程序的入口点
// 函数体内的代码
return 0; // 返回退出状态
}
double square(double x) { // 自定义函数示例
return x * x; // 函数体,计算并返回x的平方
}
4.变量声明与定义
- 变量应在使用前声明,可以在函数内部(局部变量)或外部(全局变量)定义。
- 类型声明如
int
,float
,char
等紧随变量名,例如int counter;
。
语句与表达式
包括赋值语句、控制流语句(如 if...else
,switch
,for
,while
,do...while
循环等)、函数调用、算术表达式等。
5.输入/输出
虽然C语言本身没有内建的输入/输出语句,但通过 <stdio.h>
中定义的函数如 printf()
和 scanf()
实现输入输出功能。
6.声明与初始化
变量声明时可以加上初始化,例如 int count = 0;
。
7.源文件结构
- 每个C源文件可能包含多个函数定义和其他声明,但只有一个主函数
main()
,它是程序执行的起点。 - 头文件引用(如预处理器指令
#include
) 通常出现在源文件的开头部分。
总之,C语言源代码文件是一系列预处理器指令、函数定义、变量声明与初始化、表达式和控制结构的有序组合,通过编译链接最终生成可执行文件。注释贯穿在整个源代码中,用于提升代码可读性和文档化功能。
C.程序的生命周期(编译、链接、运行)
C语言程序的生命周期大致分为以下几个阶段:
-
预处理阶段(Preprocessing)
- 在此阶段,预处理器(cpp)对源代码进行初步处理。
- 它处理所有的预处理器指令,比如
#include
引入头文件,展开#define
定义的宏,执行条件编译指令等。 - 最终生成一个扩展名为
.i
的预处理文件。
-
编译阶段(Compilation)
- 预处理后的文件被编译器(cc1)处理,编译器将其翻译成特定目标架构的汇编代码。
- 编译器检查语法错误,并确保程序逻辑正确性(语义分析)。
- 编译后的结果是一个扩展名为
.s
或.asm
的汇编语言源文件。
-
汇编阶段(Assembly)
- 汇编器(as)将汇编语言代码转换为机器语言指令,即生成目标文件(Object File)。
- 目标文件通常扩展名为
.o
(Unix/Linux系统)或.obj
(Windows系统)。 - 目标文件不仅包含机器语言代码,还包括符号表信息(如函数和变量的名字及地址)以及其他用于链接阶段的信息。
-
链接阶段(Linking)
- 如果程序包含多个源文件,每个源文件经过上述过程后都会得到一个目标文件。
- 链接器(ld)将所有相关的目标文件合并在一起,解决符号引用,创建完整的可执行程序。
- 链接过程中还会引入必要的系统库函数,确保程序调用的外部函数能被正确地定位和调用。
- 完成后,生成的是一个可执行文件(Executable File),在Unix/Linux系统中通常扩展名为
.out
或直接命名为可执行命令,在Windows系统中则是.exe文件。
-
运行阶段(Execution)
- 用户通过操作系统加载并执行生成的可执行文件。
- 当程序开始运行时,内存分配给程序使用的空间,并且程序的各个部分(代码段、数据段、堆栈等)按照预定的方式载入内存。
- 程序从
main()
函数开始执行,直至程序正常结束或者遇到异常终止。
-
装载阶段(Loading)
- 在程序执行之前,操作系统负责将可执行文件加载到内存中,设置好程序计数器指向第一条要执行的指令。
- 如果程序在运行时还需要动态加载某些模块或库,则在运行时发生动态链接。
以上就是C语言程序从源代码到可执行程序的完整生命周期。在现代集成开发环境中(IDE),这些步骤往往是自动完成并且隐藏在“构建”或“运行”按钮的背后,但对于理解底层编译原理和调试程序来说,明确每个阶段的具体工作是非常重要的。
三 C语言基本语法元素
A.C语言的数据类型(整型、浮点型、字符型等)
在C语言中,提供了多种基本数据类型,主要可以分为整型、浮点型和字符型三大类,以及其他复合类型如数组、结构体、联合体等。下面详细介绍这三大类基本数据类型:
1. 整型(Integer Types)
整型用于存储整数值,C语言中有不同大小和类型的整型变量,包括:
int
:标准整型,其大小通常足够用来表示大部分整数,但具体大小依赖于编译器和平台,一般为16位、32位或64位。short int
或short
:短整型,至少能够存储16位的整数。long int
或long
:长整型,至少与int
类型一样大,但在一些平台上可能更大。long long int
或long long
:长整型的扩展形式,至少能存储64位的整数,这是C99标准新增的类型。unsigned
前缀:与任何整型结合使用(如unsigned int
),表示无符号整型,即该类型的变量只能存储非负整数,并且对应的正数范围比有符号整型大一倍。
2. 浮点型(Floating-Point Types)
浮点型用于存储实数,精度有限,但能表示很大或很小的数值以及小数部分:
float
:单精度浮点型,通常占用32位存储空间,精度较低,但内存占用较少。double
:双精度浮点型,是C语言默认的浮点类型,通常占用64位存储空间,精度较高。long double
:扩展精度浮点型,提供的精度高于double
类型,但具体的精度和存储大小由实现决定,一般情况下占用更多字节。
3. 字符型(Character Type)
字符型用于存储单个字符,通常占8位(1字节),可以存储ASCII码或者其他字符集中的字符:
char
:字符型,除了可以存储字母、数字和其他可见字符外,还可以存储不可见字符,如控制字符。
此外,C语言还提供了枚举类型(enum
)、空类型(void
)以及指针类型等特殊类型。
对于每种类型,C语言都定义了它们的最大值和最小值(如果适用)。例如,limits.h
头文件中包含了各种整型的最大和最小值常量定义。同时,float.h
头文件中包含了浮点数的相关属性信息。
B.变量声明与使用
1.变量声明
变量声明是指在程序中告知编译器变量的类型和名称,但并不立即分配内存空间。声明变量的主要目的是让编译器提前知道即将使用的变量类型,以便进行类型检查和后续的编译过程。
声明变量的基本语法:
datatype variable_name;
例如:
int age;
float temperature;
char name[20];
这里分别声明了一个整型变量age、一个浮点型变量temperature和一个长度为20的字符数组name。
2.变量定义
变量定义则是不仅声明了变量的类型和名称,同时也为其分配了内存空间。在C语言中,通常声明和定义是同时进行的,除非使用了extern
关键字进行外部声明。
定义变量的语法与声明相似,但如果同时初始化变量,也会视为定义:
int age = 20; // 这里既是声明也是定义,同时初始化为20
变量的作用域和生命周期
- 局部变量:在函数内部声明的变量,其作用域限于声明它的函数内部,当函数执行完毕后,局部变量的生命周期结束,内存空间会被释放。
- 全局变量:在函数外部(通常是在所有函数之上)声明的变量,其作用域是整个程序,生命周期从程序开始执行时一直持续到程序结束。
变量的命名规则
- 变量名必须以字母或下划线
_
开始,后面可以跟字母、数字或下划线。 - 不得使用C语言的关键字作为变量名。
- 变量名区分大小写。
3.变量的使用
在声明和定义变量后,就可以在程序中使用它们进行各种操作,包括赋值、读取、传递给函数以及在表达式中使用等。
4.示例
#include <stdio.h>
int main() {
int myNumber; // 声明并定义了一个整型变量myNumber
myNumber = 10; // 给变量赋值
printf("The value of myNumber is: %d\n", myNumber); // 输出变量的值
char myString[] = "Hello World!"; // 声明并定义了一个字符串变量,并初始化
return 0;
}
在这个例子中,myNumber
是一个整型变量,首先声明并定义,然后赋值并输出。myString
是一个字符数组(字符串)变量,声明并定义的同时进行了初始化。
C.常量和符号常量
在C语言中,常量和符号常量是用来表示程序中固定不变的值的术语。
1.常量(Constants):
常量是程序执行过程中其值始终保持不变的数据对象。C语言中的常量分为几种类型:
- 整型常量:如
-123
、0xFF
(十六进制)、022
(八进制)等。 - 实型常量(浮点数):如
3.14
、3.14f
(单精度浮点数)、3.14L
或3.14lf
(双精度浮点数)。 - 字符常量:用单引号括起来的单个字符,如
'A'
、' '
(空格)、'\n'
(换行符)等。字符常量在内存中是以整型的形式存储其ASCII码值的。 - 字符串常量:用双引号括起来的字符序列,如
"Hello World"
。注意,字符串常量实际上是一个字符数组,末尾有一个隐含的结束符\0
。
2.符号常量(Symbolic Constants 或 Macros):
符号常量是通过预处理器(preprocessor)定义的,其特点是用一个标识符来代替一个固定的值,一旦定义后,在整个程序中该标识符就代表了这个固定值。符号常量有两种主要定义方式:
宏定义(Macro):使用#define
关键字定义,例如:
#define PI 3.14159265358979323846
#define MAX_ELEMENTS 100
这里的 PI
和 MAX_ELEMENTS
是符号常量,编译时会被相应的值替换。
const关键字定义:在C99标准以后,也可以使用const
关键字定义常量,这种方式定义的常量具有类型,并在编译阶段确定其值,而不是简单地文本替换。例如:
const int MY_CONSTANT = 12345;
-
此处的
MY_CONSTANT
是一个具有类型为int
的常量,其值在编译时就不能再更改。
符号常量的优点在于提高代码的可读性和可维护性,当某个值在程序中多处使用时,只需修改一处定义即可更新所有引用该符号常量的地方。
D.运算符与表达式
运算符
运算符是C语言中用于执行特定操作的符号,它们可以改变、比较或合并变量和值。C语言中的运算符分为以下几类:
-
算术运算符:
+
(加)-
(减)*
(乘)/
(除)%
(取模或求余数)
-
关系运算符:
==
(等于)!=
(不等于)<
(小于)>
(大于)<=
(小于或等于)>=
(大于或等于)
-
逻辑运算符:
&&
(逻辑与)||
(逻辑或)!
(逻辑非)
-
位运算符:
&
(按位与)|
(按位或)^
(按位异或)~
(按位取反)<<
(左移)>>
(右移)
-
赋值运算符:
=
(简单赋值)+=
、-=
、*=
、/=
、%=
、<<=
、>>=
、&=
、^=
、|=
(复合赋值)
-
条件运算符(三目运算符):
condition ? expr1 : expr2
,根据条件condition
的真假,计算并返回expr1
或expr2
的结果。
-
自增自减运算符:
++
(前置或后置自增)--
(前置或后置自减)
-
sizeof运算符:
sizeof
用于计算数据类型或变量所占内存空间的大小。
表达式
表达式是由运算符、操作数(可以是变量、常量、函数调用或其它表达式)以及括号组成的合法序列。C语言中的表达式根据运算符的优先级和结合性规则进行计算。表达式的结果可以是一个值,也可以是一个新的变量值(如赋值表达式的结果是赋值后变量的新值)。
例如:
int a = 5, b = 10;
int result;
// 算术表达式
result = a + b; // 结果为15
// 关系表达式
bool equal = a == b; // 结果为false
// 赋值表达式
a += b; // 相当于 a = a + b; a的值变为15
// 条件表达式
char grade = (score >= 90) ? 'A' : 'B'; // 根据分数给出等级
// 位运算表达式
int flag = a & 1; // 获取a的最低位
C语言中表达式的求值严格遵循运算符优先级和结合性规则,必要时可以通过圆括号(()
)来强制改变运算顺序。