C 语言基础,来喽!(二)

简介: C 语言是一门抽象的、面向过程的语言,C 语言广泛应用于底层开发,C 语言在计算机体系中占据着不可替代的作用,可以说 C 语言是编程的基础,也就是说,不管你学习任何语言,都应该把 C 语言放在首先要学的位置上。下面这张图更好的说明 C 语言的重要性

剖析 hello 程序的执行过程

前面我们简单的介绍了一下计算机的硬件的组成和操作,现在我们正式介绍运行示例程序时发生了什么,我们会从宏观的角度进行描述,不会涉及到所有的技术细节

刚开始时,shell 程序执行它的指令,等待用户键入一个命令。当我们在键盘上输入了 ./hello 这几个字符时,shell 程序将字符逐一读入寄存器,再把它放到内存中,如下图所示

微信图片_20220417155359.png

当我们在键盘上敲击回车键的时候,shell 程序就知道我们已经结束了命令的输入。然后 shell 执行一系列指令来加载可执行的 hello 文件,这些指令将目标文件中的代码和数据从磁盘复制到主存。

利用 DMA(Direct Memory Access) 技术可以直接将磁盘中的数据复制到内存中,如下

微信图片_20220417155404.png

一旦目标文件中 hello 中的代码和数据被加载到主存,处理器就开始执行 hello 程序的 main 程序中的机器语言指令。这些指令将 hello,world\n 字符串中的字节从主存复制到寄存器文件,再从寄存器中复制到显示设备,最终显示在屏幕上。如下所示

微信图片_20220417155407.png

高速缓存是关键

上面我们介绍完了一个 hello 程序的执行过程,系统花费了大量时间把信息从一个地方搬运到另外一个地方。hello 程序的机器指令最初存储在磁盘上。当程序加载后,它们会拷贝到主存中。当 CPU 开始运行时,指令又从内存复制到 CPU 中。同样的,字符串数据 hello,world \n 最初也是在磁盘上,它被复制到内存中,然后再到显示器设备输出。从程序员的角度来看,这种复制大部分是开销,这减慢了程序的工作效率。因此,对于系统设计来说,最主要的一个工作是让程序运行的越来越快。

由于物理定律,较大的存储设备要比较小的存储设备慢。而由于寄存器和内存的处理效率在越来越大,所以针对这种差异,系统设计者采用了更小更快的存储设备,称为高速缓存存储器(cache memory, 简称为 cache 高速缓存),作为暂时的集结区域,存放近期可能会需要的信息。如下图所示

微信图片_20220417155410.png

图中我们标出了高速缓存的位置,位于高速缓存中的 L1高速缓存容量可以达到数万字节,访问速度几乎和访问寄存器文件一样快。容量更大的 L2 高速缓存通过一条特殊的总线链接 CPU,虽然 L2 缓存比 L1 缓存慢 5 倍,但是仍比内存要哦快 5 - 10 倍。L1 和 L2 是使用一种静态随机访问存储器(SRAM) 的硬件技术实现的。最新的、处理器更强大的系统甚至有三级缓存:L1、L2 和 L3。系统可以获得一个很大的存储器,同时访问速度也更快,原因是利用了高速缓存的 局部性原理。

Again:入门程序细节

现在,我们来探讨一下入门级程序的细节,由浅入深的来了解一下 C 语言的特性。

#include<stdio.h>

我们上面说到,#include<stdio.h> 是程序编译之前要处理的内容,称为编译预处理命令。

预处理命令是在编译之前进行处理。预处理程序一般以 # 号开头。

所有的 C 编译器软件包都提供 stdio.h 文件。该文件包含了给编译器使用的输入和输出函数,比如 println() 信息。该文件名的含义是标准输入/输出 头文件。通常,在 C 程序顶部的信息集合被称为 头文件(header)

C 的第一个标准是由 ANSI 发布的。虽然这份文档后来被国际标准化组织(ISO)采纳并且 ISO 发布的修订版也被 ANSI 采纳了,但名称 ANSI C(而不是 ISO C) 仍被广泛使用。一些软件开发者使用ISO C,还有一些使用 Standard C

C 标准库

除了 <sdtio.h> 外,C 标准库还包括下面这些头文件

微信图片_20220417155416.png

<assert.h>

提供了一个名为 assert 的关键字,它用于验证程序作出的假设,并在假设为假输出诊断消息。

<ctype.h>

C 标准库的 ctype.h 头文件提供了一些函数,可以用于测试和映射字符。

这些字符接受 int 作为参数,它的值必须是 EOF 或者是一个无符号字符

EOF是一个计算机术语,为 End Of File 的缩写,在操作系统中表示资料源无更多的资料可读取。资料源通常称为档案或串流。通常在文本的最后存在此字符表示资料结束。

<errno.h>

C 标准库的 errno.h 头文件定义了整数变量 errno,它是通过系统调用设置的,这些库函数表明了什么发生了错误。

<float.h>

C 标准库的 float.h 头文件包含了一组与浮点值相关的依赖于平台的常量。

<limits.h>

limits.h 头文件决定了各种变量类型的各种属性。定义在该头文件中的宏限制了各种变量类型(比如 char、int 和 long)的值。

<locale.h>

locale.h 头文件定义了特定地域的设置,比如日期格式和货币符号

<math.h>

math.h 头文件定义了各种数学函数和一个宏。在这个库中所有可用的功能都带有一个 double 类型的参数,且都返回 double 类型的结果。

<setjmp.h>

setjmp.h 头文件定义了宏 setjmp()、函数 longjmp() 和变量类型 jmp_buf,该变量类型会绕过正常的函数调用和返回规则。

<signal.h>

signal.h 头文件定义了一个变量类型 sig_atomic_t、两个函数调用和一些宏来处理程序执行期间报告的不同信号。

<stdarg.h>

stdarg.h 头文件定义了一个变量类型 va_list 和三个宏,这三个宏可用于在参数个数未知(即参数个数可变)时获取函数中的参数。

<stddef.h>

stddef .h 头文件定义了各种变量类型和宏。这些定义中的大部分也出现在其它头文件中。

<stdlib.h>

stdlib .h 头文件定义了四个变量类型、一些宏和各种通用工具函数。

<string.h>

string .h 头文件定义了一个变量类型、一个宏和各种操作字符数组的函数。

<time.h>

time.h 头文件定义了四个变量类型、两个宏和各种操作日期和时间的函数。

main() 函数

main 函数听起来像是调皮捣蛋的孩子故意给方法名起一个 主要的 方法,来告诉他人他才是这个世界的中心。但事实却不是这样,而 main() 方法确实是世界的中心。

C 语言程序一定从 main() 函数开始执行,除了 main() 函数外,你可以随意命名其他函数。通常,main 后面的 () 中表示一些传入信息,我们上面的那个例子中没有传递信息,因为圆括号中的输入是 void 。

除了上面那种写法外,还有两种 main 方法的表示方式,一种是 void main(){} ,一种是 int main(int argc, char* argv[]) {}

  • void main() 声明了一个带有不确定参数的构造方法
  • int main(int argc, char* argv[]) {} 其中的 argc 是一个非负值,表示从运行程序的环境传递到程序的参数数量。它是指向 argc + 1 指针数组的第一个元素的指针,其中最后一个为null,而前一个(如果有的话)指向表示从主机环境传递给程序的参数的字符串。如果argv [0]不是空指针(或者等效地,如果argc> 0),则指向表示程序名称的字符串,如果在主机环境中无法使用程序名称,则该字符串为空。

注释

在程序中,使用 /**/ 的表示注释,注释对于程序来说没有什么实际用处,但是对程序员来说却非常有用,它能够帮助我们理解程序,也能够让他人看懂你写的程序,我们在开发工作中,都非常反感不写注释的人,由此可见注释非常重要。

微信图片_20220417155425.png

C 语言注释的好处是,它可以放在任意地方,甚至代码在同一行也没关系。较长的注释可以多行表示,我们使用 /**/ 表示多行注释,而 // 只表示的是单行注释。下面是几种注释的表示形式

// 这是一个单行注释
/* 多行注释用一行表示 */
/*
  多行注释用多行表示
    多行注释用多行表示
      多行注释用多行表示
        多行注释用多行表示
*/

函数体

在头文件、main 方法后面的就是函数体(注释一般不算),函数体就是函数的执行体,是你编写大量代码的地方。

变量声明

在我们入门级的代码中,我们声明了一个名为 number 的变量,它的类型是 int,这行代码叫做 声明,声明是 C 语言最重要的特性之一。这个声明完成了两件事情:定义了一个名为 number 的变量,定义 number 的具体类型。

int 是 C 语言的一个 关键字(keyword),表示一种基本的 C 语言数据类型。关键字是用于语言定义的。不能使用关键字作为变量进行定义。

示例中的 number 是一个 标识符(identifier),也就是一个变量、函数或者其他实体的名称。

###变量赋值

在入门例子程序中,我们声明了一个 number 变量,并为其赋值为 11,赋值是 C 语言的基本操作之一。这行代码的意思就是把值 1 赋给变量 number。在执行 int number 时,编译器会在计算机内存中为变量 number 预留空间,然后在执行这行赋值表达式语句时,把值存储在之前预留的位置。可以给 number 赋不同的值,这就是 number 之所以被称为 变量(variable) 的原因。

微信图片_20220417155430.png

printf 函数

在入门例子程序中,有三行 printf(),这是  C 语言的标准函数。圆括号中的内容是从 main 函数传递给 printf 函数的。参数分为两种:实际参数(actual argument)形式参数(formal parameters)。我们上面提到的 printf 函数括号中的内容,都是实参。

相关文章
|
5月前
|
存储 编译器 程序员
C++语言基础学习
C++语言基础学习
|
5月前
|
存储 编译器 C++
|
6月前
|
算法 编译器 C++
C/C++面试题之语言基础篇(二)
C/C++面试题之语言基础篇(二)
82 0
|
6月前
|
存储 编译器 C语言
C/C++面试题之语言基础篇(一)
C/C++面试题之语言基础篇(一)
169 0
|
安全 Java C#
C#语言基础知识
C#语言基础知识
58 0
|
安全 程序员 C语言
|
Java Python
Python编程语言基础_语法入门
Python语言基础 - 语法入门、计算机常识、常用的 dos 命令、环境变量(environment variable)
158 0
Python编程语言基础_语法入门
|
存储 编译器 程序员
C++语言基础篇(二)
C++语言基础篇(二)
|
IDE Java 开发工具
Python3入门笔记七之面向对象高级编程
&#39;限制实例的属性:__slots__ ,把一个方法变成属性调用:@property装饰器,多重继承&MixIn,定制类,枚举类:Enum,元类&#39; 限制实例的属性:__slots__ 限制实例的属性 比如只允许对Student实例添加name和age属性。 由于&#39;score&#39;没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。注意:__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
181 0