C语言笔记(第n版):入门知识

Ⅰ、C语言程序的基本结构

一个最简单的入门C语言程序:

#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    return 0;
}

C语言的基本结构可以包括以下几个方面:

1、头文件 #include<文件名>

        对于一个程序而言,可以没有输入,但是要有输出,否则,即使程序真的做了什么,我们也是看不到的,对于初学者而言,输出才能知道程序真的做了什么。对于输出,初学者需要的是调用一个函数(完成某个特定功能的一系列操作),对于上面程序则是printf函数,它将括号里面的内容(Hello, World!\n)打印在一个叫做控制台Console的窗口界面上。而这个函数具体的操作在某个叫做stdio.h 标准输入输出头文件中,所以需要将其包含include进来。

2、函数

  • C语言由函数构成,每个程序可以包含多个函数。
  • 函数是一段完成特定任务的代码块(由花括号{}及里面的内容组成)以及函数签名(比如int main())组成,可以被其他函数或主函数调用执行。

3、主函数

  • 每个C语言程序都有且仅有一个main函数,它是程序的入口点。
  • main函数具有返回值,一个数字(return 0;返回0,表示程序正常结束),用于表示程序的退出状态码。
  • 当程序开始执行时,操作系统会调用main函数,并从该函数开始执行程序。
  • main函数的结束标志着程序的结束。

4、语句

  • 每个语句以分号作为结束标志,表示一条指令的结束。
  • 可以使用花括号将多条语句包含在一个语句块中,形成复合语句。

Ⅱ、C语言程序的基本组成

基本元素

        C语言中的基本元素包括关键字、标识符、字面量、运算符、分隔符、注释等,它们组成了语句和函数。

关键字

        关键字是C语言中具有特定功能的保留字,它们在程序中被赋予特定的意义和功能。关键字在程序中具有特殊的语法作用,不能用作其他用途。ANSI标准定义了32个C语言的关键字,包括数据类型关键字、流程控制关键字和标识符关键字等。

关键字

简单说明

void

无类型

char

字符型

int

整型

float

单精度浮点数

double

双精度浮点数

short

短整型

long

长整型

signed

有符号类型

unsigned

无符号类型

struct

结构体类型

union

联合体类型

enum

枚举类型

typedef

类型定义

sizeof

计算数据类型或变量所占用的内存大小

auto

自动类型提升

register

寄存器优化

extern

用于声明外部变量或函数

const

常量

volatile

易变变量

static

静态变量

流程控制关键字

简单说明

return

从函数中返回一个值

continue

跳过当前循环的剩余部分,进入下一次循环

break

无条件跳出循环或switch语句

goto

无条件跳转到指定的标签位置

if

条件判断和分支结构

else

如果条件不满足时执行的分支结构

switch

多分支选择结构

case

switch语句中的条件分支

default

switch语句中没有匹配到的情况

for

循环结构

do

do-while循环结构

while

循环结构

标识符

        标识符是用来命名变量、函数、数组等的名称。标识符由字母、数字和下划线组成,且必须以字母或下划线开头。标识符在程序中用于声明变量、调用函数和访问数据等操作。

以下为一些正确的标识符

_abc     king    think   book

字面量

        字面量是程序中使用的固定值或常量,整数、浮点数、字符、字符串等形式。字面量在程序中直接表示具体的数值或字符,具有常量性。

运算符

        运算符用于对数据进行操作和计算。C语言提供了多种运算符,包括算术运算符(如加法、减法、乘法、除法)、关系运算符(如等于、不等于)、逻辑运算符(如与、或、非)等。运算符用于连接表达式,实现各种计算和逻辑判断。

分隔符

        分隔符用于将代码块或语句分隔开来,使代码更加清晰易读。C语言中的常见分隔符包括分号(;)、换行符(\n)、花括号({})等。它们用于标识代码的起止位置,确保程序的逻辑正确性。

注释

        注释是对代码的解释和说明,其目的是让人们能够更加轻松地了解代码。注释是编写程序时,写程序的人给一个语句、程序段、函数等的解释或提示,能提高程序代码的可读性。注释只是为了提高可读性,不会被计算机编译。在C语言中有两种注释方法:单行注释 多行注释

// 单行注释以//开头,到行尾全算是注释内容
int integer_number = 12;
//上述语句 关键字(int) 标识符(integer_number) 运算符(=) 字面量(12) 分隔符(;)当然空格也算,作为区分基本元素 
/*
两个斜杆配合*组成一个多行注释区
*/

基本逻辑

        前面说过,任何一个完整的C语言程序,以main函数为执行入口,一旦main函数结束,程序也就结束了。这是程序的大体逻辑,或者说是嵌套逻辑,比如以下两个程序:

// pragam1
#include<stdio.h>

int main()
{
    printf("begin main!\n");
    if(1){
        printf("it's 1\n");

    }else{
        printf("it's not 1\n");

    }
    printf("end main!\n");
    return 0;
}
// pragam2
#include<stdio.h>

int main()
{
    printf("begin main!\n");
    if(0){
        printf("it's 1\n");

    }else{
        printf("it's not 1\n");

    }
    printf("end main!\n");
    return 0;
}

        两个程序十分相像,但是结果不同,第一个输出

        第二个输出

        因为分支逻辑的存在,程序的具体执行流向存在了可选择的路径。这类似于从一个水源离开的水流,无论经过何种路径都总将流向大海,程序的奇妙就在于这经过的路径的千变万化。

Ⅲ、编程机制

        一个可供人阅读、理解乃至编写的C语言程序(源代码)要让计算机去理解与执行,需要将我们的源码翻译成二进制可执行程序。

        这个“翻译”通常分为两种方式:

        一种叫做编译(compliation),一种叫做解释(interpretation)。使用编译的编程语言,可称之为编译型语言,编译即将要运行的程序全部翻译成二进制代码形式然后执行;使用解释方式的编程语言,也称之为解释型编程语言,只有执行到某条语句时,某条语句才会翻译成二进制代码形式。

        C属于前者。下面通过命令行的形式(这相当原始,对于习惯使用IDE的编程人员而言),讲解C语言程序的编译过程,这里使用的命令在Linux和Windows操作系统下是基本通用的。

编写hello world C程序:

// hello.c

#include <stdio.h>

int main(){

  printf("hello world!\n");

}

        编译C语言程序需要使用到一个编译器gcc

GCC,全称为GNU Compiler Collection(GNU编译器套件),是GNU项目下的一个开源编译器集合,支持多种编程语言的编译。

        上述gcc命令成功将一个hello.c的C源程序翻译成了一个可执行的二进制程序。

        通用的,编译一个单一的源文件并生成可执行文件,可以使用如下命令:

gcc source_file.c -o output_executable

        其中,source_file.c是源代码文件名,.c表明这是C语言源文件,-o output_executable指定输出的可执行文件名。

        如果程序中没有main函数,或者说没有写正确,就会有如下错误 Undefined reference to `WinMain@16`:

        虽然以上的命令一步到位将源代码翻译成了二进制的可执行文件,但这并不意味着,转换是一步到位的。为了特别的需要,我们也可以一步步生成一个C语言的可执行程序,以下将从四个步骤依次“编译” C程序,这也是以上命令在背后的执行过程。

1. 预处理(Preprocessing)

        预处理阶段用于处理源代码中的预处理指令,并生成预处理后的源文件。使用以下命令进行预处理:

gcc -E source.c -o source.i

        其中,source.c是源代码文件,source.i是预处理后的文件。是C预处理器和C编译器之间的中间(intermediate)文件

        可以看到i文件与源代码文件相比扩大了22倍,这时候的i文件仍然是文本格式,可以打开阅读:

        源代码的内容大部分在文本最后可以看到,那么前面的多出来的是什么,其实就是stdio.h头文件里面的内容,即#include指令在预处理时将替换为被包含的文件。

        为了验证这一点,这里做一个实验如下,这里创建了一个自己的头文件,并使用include指令,注意,指令应该独占一行。我们直接编译,结果编译成功。

        接下来试试预处理,可以验证,在预处理后,头文件被包含了进来,至于其它的,我也不知道是什么东西。

        除了include指令,在预处理阶段也会进行其它指令的处理,比如define,不过这里没有涉及,但是主要的作用都类似,都是一个替换。

2. 编译(Compilation)

        这里的编译不是指程序从源文件到二进制程序的全部过程,而是指将经过预处理之后的程序转换成特定汇编代码(assembly code)的过程。编译的指定如下:

        编译阶段将预处理后的源文件转换为汇编代码或目标文件。使用以下命令进行编译:

gcc -S source.i -o source.s

        或者直接将编译和预处理合并成一步:

gcc -S source.c -o source.s

        其中,source.i是预处理后的文件,source.s是汇编代码文件。 s文件是汇编程序。

        经过编译后的文件,可以看到体积缩小了,和源代码的文件大小相同,此时的S文件也是可读的,不过可读性进一步降低了。

        至于为什么大小回到了正常大小,读者可以认为,我们只需要程序运行实际需要的东西,而把不需要的剔除了。 

3. 汇编(Assemble)

        汇编阶段将汇编代码转换为机器语言的目标文件。使用以下命令进行汇编:

gcc -c source.s -o source.o

        其中,source.s是汇编代码文件,source.o是目标文件。 o文件是obj文件,程序编译时生成的中间代码文件。目标文件,一般是程序编译后的二进制文件,再通过链接器和资源文件链接就成可执行文件了。OBJ只给出了程序的相对地址,而可执行文件是绝对地址。-c 选项表示只编译而不链接。

4. 链接(Linking)

        链接阶段将多个目标文件和库文件组合在一起,生成可执行文件或动态库文件。使用以下命令进行链接:

gcc source1.o source2.o -o executable

        或者也可以使用以下方式链接库文件:

gcc source.o -llibrary -o executable

        其中,source1.osource2.o是目标文件,executable是生成的可执行文件。-l选项用于指定链接的库文件,library是库文件的名称。

        链接两个文件:

gcc  -c  program1.c  -o  program1.o

gcc  -c  program2.c  -o  program2.o

gcc  program1.o  program2.o  -o  program3.exe

        后面两步操作在实际程序的运行过程中,还会涉及到其他问题而导致出错,后面会一一说明。


        以上基于我的个人理解,可能有不对不全面的地方,请读者自行斟酌,注意实践。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值