C语言深度理解-关键字(1)

序言

C语言起始于1972年,到今年(2023年)已经50个年头了,如今在各大排行榜上也占据前3的位置,经久不衰,值得我们好好研究。

许多人觉得C语言太简单/C语言指针很难,这两种想法,终究原因是只学习“语言”的属性,不关心各种计算机语言其实是为了解决人类的问题而发明的,而且是真正要跑在计算机上的,

我们不能只谈论语言本身,而忽视了实际运行时的环境,C语言深入的学习还需要了解计算机操作系统、计算机组成原理、计算机体系结构等相关知识。注意:这里只是需要用到相关知识。

C语言的发明其实用来开发Unix操作系统的,所以值得我们去学习,并将上述计算机理论原理相关知识融入其中。(如:CPU和内存到底是什么?如何存/取出一个数据?)

基于上述,我写下了如下的C语言深度理解。

(希望大家点点关注!!!若有什么错误之处,可以直接指出,望各位大佬指教。)

​ 写于 2023年7月26日


C语言至少需要知道的C89/C90中32个关键字

关键字的分类

C语言一共多少个关键字呢?一般的书上,都是32个(包括本书),但是这个都是 C90(C89) 的标准。其实 C99 后又新增 了5个关键字(在C99标准中加⼊了 inlinerestrict_Bool_Comploex_Imaginary 等关键字)。不过,目前主流的编译器,对 C99 支持的并不好,我们后面默认情况,使用 C90 ,即,认为32个。

实际上目前的C语言标准(C23) (本人认为目前了解C11之后的即可)

下面是C语言关键字参考链接:

  1. C 关键词 - cppreference.com

在这里插入图片描述

  1. C语言程序设计:现代方法(第2版•修订版) (K.N.King) / C Primer Plus (第六版 )(C11)

    在这里插入图片描述

下面我们来看具体32个关键字的作用

关键字解释
auto声明自动变量
short声明短整型变量或函数
int声明整型变量或函数
long声明长整型变量或函数
float声明单精度浮点型变量或函数
double声明双精度浮点型变量或函数
char声明字符型变量或函数
struct声明结构体变量或函数
union声明共用(联合)数据类型
enum声明枚举类型
typedef用以给数据类型取别名
const声明只读变量(注:C语言中,const类型限定符声明的是变量,不是常量)
unsigned声明无符号类型变量或函数
signed声明有符号类型变量或函数
extern声明变量是在其他文件正声明
register声明寄存器变量
static声明静态变量
volatile说明变量在程序执行中可被隐含地改变
void声明函数无返回值或无参数,声明无类型指针
if条件语句
else条件语句否定分支(与 if 连用)
switch用于开关语句
case开关语句分支
for一种循环语句
do循环语句的循环体
while循环语句的循环条件
goto无条件跳转语句
continue结束当前循环,开始下一轮循环
break跳出当前循环
default开关语句中的“其他”分支
return子程序返回语句(可以带参数,也可不带参数)循环条件
sizeof计算数据类型长度

第一个C程序 - 补充内容

// Visual Studio 2019(下面简称:VC2019)中建立项目/vscode远程ssh + linux(Ubuntu 22.04 LTS)创建C源文件
// 编写第一个C程序"hello world"
#include <stdio.h>
int main()
{
	printf("hello world!\n");
	return 0;
}

//1.运行程序的方式,当然可以用VC直接启动(按Ctrl + F5就可以直接运行)
//2.当然,也可以在VC项目中,找到代码生成的二进制可执行程序,双击即可。(Linux平台下通过找到生成的可执行程序,通过命令行运行)
//3.所以:我们的角色是写代码,编译器的角色是把文本代码变成二进制可执行程序。
//4.双击?不就是windows下启动程序的做法吗?
//5.那么启动程序的本质是什么呢?将程序数据,加载到内存中,让计算机运行!
//6.那么为什么要加载到内存中呢?

下面我们回答这6个问题:

  1. VC 2019 其中是以项目为单位来运行C语言程序的,其中集成了快捷功能(运行、调试)。若在Linux平台下运行C语言程序,则要创建如test.c的源文件,通过gcc/clang等编译器来生成可执行程序(也可以通过装插件来实现类似VC 2019的快捷功能)。

VC 2019 调试等快捷功能

vscode + ssh相关插件 + linux等快捷功能

  1. 下面是VC 2019的演示:

    VC 2019中可以通过快捷键来运行,前面已经概述过。

    VC 2019 通过快捷键一键运行结果

    其实通过快捷键运行后会生成可执行程序,他在我们的C:\Users\Administrator\Desktop\demo\test_7_26\Debug目录下,会生成test_7_26.exe可执行程序。我们双击它就可以运行程序。我们会发现屏幕一闪而过,原因是程序运行完就自动关闭了,若想看到运行时的效果,要在头文件加入 #include <windows.h> windows.h系统头文件,作用是为了停屏,然后在return 0前一行加一句 system("pause"); pause是为了停屏。

    代码如下:

    #include <stdio.h>
    #include <windows.h> //windows.h系统头文件,作用是是为了停屏
    int main()
    {
    	printf("hello world!\n");
    	system("pause"); //pause是停屏
    	return 0;
    }
    

    我们通过快捷键运行后,发现屏幕会多显示一行文字:请按任意键继续. . .成功起到停屏作用。

    VC 2019下起到停屏作用

    接下来,我们查看C:\Users\Administrator\Desktop\demo\test_7_26\Debug目录下,生成test_7_26.exe可执行程序。

    VC2019 下生成的test_7_26.exe可执行程序

    我们双击运行它,得到如下结果:

    在这里插入图片描述

    ​ 双击test_7_26.exe可执行程序。

    说明这个生成的可执行程序就和我们双击QQ/网易云音乐等程序一样,没什么区别。

    下面是Linux平台下的演示:

    接下来我们来看一下Linux平台下的执行流程:首先我们先查看gcc版本,通过 gcc -v命令查看,我们得到以下结果

    root@ser836639051336:~# gcc -v
    Using built-in specs.
    COLLECT_GCC=gcc
    COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper
    OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
    OFFLOAD_TARGET_DEFAULT=1
    Target: x86_64-linux-gnu
    Configured with: ../src/configure -v --with-pkgversion='Ubuntu 11.3.0-1ubuntu1~22.04.1' --with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-11 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-11-aYxV0E/gcc-11-11.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-11-aYxV0E/gcc-11-11.3.0/debian/tmp-gcn/usr --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2
    Thread model: posix
    Supported LTO compression algorithms: zlib zstd
    gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04.1) 
    

    查看最后一条信息得到使用的gcc版本:gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04.1)

    我们使用的平台是 Target: x86_64-linux-gnu。插入一个题外话:市面上大多数是 X86-64 体系架构的Linux服务器,当然也有arm架构的服务器。

    我们通过 gcc编译命令gcc test.c - o test生成test的可执行程序。Linux中通过 ./+可执行程序文件名来运行程序。得到结果如下:

    在这里插入图片描述

    下面是执行的相关命令:

    root@ser836639051336:~/test_7_26# gcc test.c -o test
    root@ser836639051336:~/test_7_26# ls
    test  test.c
    root@ser836639051336:~/test_7_26# ./test 
    hello world!
    root@ser836639051336:~/test_7_26# 
    

    我们发现成功打印了hello word!,说明和在Windows平台下运行的结果一致。(看到了一点点的C语言跨平台性,其实这里使用的是不同的编译器,他们支持的C语言标准可能不同,而且都有自己编译器扩展的C语言标准,当然,大部分情况下,相同的代码都是能跨平台编译的)

  2. 作为编程者的我们,我们的目的是编写各种计算机语言的代码,解决相关问题,我们编写代码是文本的代码,是人能通过字面意思直接识别的,而生成的二进制程序我们用文本编辑器打开是乱码的,我们的编程人员很难看懂这段二进制序列,因为每台机器所支持的指令集和架构是不同的(最早开始编程的时候,是在纸带上打小孔,来标识0和1的序列来编写程序,可想而知,这种编程效率是有多么低,这里还出现了Bug这个词的来源,Bug的英文翻译是小虫子,而Bug的来是,在早期的计算机是由很多大的真空管组成的,会产生大量的光和热,引来一只小虫子钻进了真空管,导致整个机器死机了,后来被人们将计算机错误称为Bug)上面的历史故事也许你听起来很有趣,其实还有很多计算机的故事,只是我们在学习知识的时候,可能忽视背后的故事。

下面我们来看一下二进制可执行程序是什么,我们这里以Linux平台为例子,通过vscode自带的编辑器的功能打开test这个程序

在这里插入图片描述

我们发现有相关提示,我们点击仍然打开,选择图示的编辑器 Hex Editor(通过vscode 插件市场搜索这个名字就可以安装)

在这里插入图片描述

我们打开后发现其中有往屏幕(终端)hello world!这段二进制代码,看起来很奇怪?其实计算机显示到屏幕的文字是相应的字符。

在这里插入图片描述

我们目前这么理解就可以了,后面我还要谈论字符/字符集的概念。

  1. 在windows下双击启动程序的做法,我们看起来很简单,其实其中涉及不少知识。首先,我们补充一些操作系统相关的知识:

    程序是很多二进制序列的集合,我们的程序是放在硬盘上的,硬盘就是我们经常说的HDD(机械硬盘)/SSD(固态硬盘),当然现在的笔记本/台式机基本上都是固态硬盘,因为固态硬盘读写速度特别快,有的比机械硬盘快十几~一百倍,如果你去各大网购平台搜索固态硬盘,你会发现有PClE 4.0 /PCLE 3.0/STAT的m.2固态硬盘,比如PCLE 4.0的固态硬盘读写速度可以到达7000MB/s,看起来很快吧,而普通机械硬盘读写速度就100-200MB/s,但是机械硬盘虽然读写速度看起来很慢,他里面存储的数据时间是最长的,而固态硬盘是有读写寿命的,你可以理解为固态硬盘经常读写,到了一定时间,会发生掉速/掉盘等事情,当然,只要你购买的是大品牌的固态硬盘,在规定的保修时间(可能有5年)和 规定的读写容量范围内,会提供返厂/换新服务,这里不得不说,最近的固态硬盘和白菜一样便宜,这其中最大的功劳就是–国产之光长江存储发售的致态系列固态硬盘,让各大外国厂商都不敢随便因为失火,停电的原因来涨价。说了这么多,我们回到主题,在在windows下双击启动程序,操作系统会将存放在硬盘上的程序加载到内存中,变成我们所说的进程。

  2. 启动程序的本质就是操作系统将程序加载到内存中,变成进程,然后在计算机上运行。

    程序为什么要加载到内存,这里可能有许多疑惑,因为内存比硬盘快很多,这里说很多可能没有具体概念,目前主流的内存是DDR4和 DDR5 (DDR3只有很老的机器还在用,本人有台2010年的机器,其中的内存条就是DDR3的),除次之外,还要服务器专用ECC纠错内存,比如 DDR5-6200规格的速度可以超过100GB/s的度,DDR4 3600的内存读写速度有50GB/s,注意这里的单位是GB/s,比我们的硬盘读写速度快了很多,所以我们要程序加载到内存。其实这样的解释有点只知表象了,要深刻理解这个问题还要了解计算机组成原理中的冯诺依曼结构。

  3. 现代计算机也是基于冯诺依曼结构设计的,只有宏观上明白了计算机是由什么部件构成的,才知道为什么有内存?冯诺依曼结构如下:由五个部分组成(运算器、控制器、存储器、输入设备、输出设备)

在这里插入图片描述

​ 这里的输入设备就是我们经常提到的鼠标,键盘,硬盘,存储器就是内存,输出设备就是我们的显示器。可能看这个图还是不理解,我们举个真实的计算机的例 子(摘取CSAPP):

在这里插入图片描述

​ 通过上面的例子,我们可以看一下周围的计算机机箱,里面的各个硬件也对应图上所描述的部件,这里我们不解释其中每个具体作用,只了解大概就行,整个计

​ 算计执行屏幕打印hello world!这个程序的流程大概是这样的(摘取自哈工大csapp课件)

在这里插入图片描述

  1. 要回答为什么程序要加载到内存,则要回答上面提到的缓存是什么??这里的内存就是磁盘的缓存,这里我讲一下原因:因为前面提到过硬盘和内存(主存)的速度相差很大,CPU直接从硬盘读取速度太 慢了,所以我们设计了内存作为缓存,这里有个问题,我们的内存通常只有8GB/16GB/32GB/64GB,而我们的硬盘有1-2TB,如何保证,计算机cpu每次取到的数据(二进制序列)都是内存中有的呢/或者我们cpu将要访问的数据大部分在内存中,这里要提到一个概念了:局部性原理,即程序具有访问局部区域里的数据和代码的趋势。通过让内存里存放可能经常访问的数据,大部分的操作都在比硬盘快的内存中完成。我们在后面还要提到存储器的层次结构,使用这种缓存计算机,可以在成本和速度方面做一个折中,让我们现在人人都买的起电脑。总的来说,硬盘上的程序先加载进入内存,变成进程,由CPU向内存读取数据来运行程序。

定义与声明 - 补充内容

什么是变量(是什么)

变量是在内存中开辟特定大小的空间,用来保存数据。

这里我们提到了一个关键字:内存,我们在前面讲述了内存是什么,但是这里所指的内存是虚拟内存,不是真实的物理内存。(这个知识点是操作系统相关的,这里不进行深刻讲解)

如何定义变量(怎么用)

int x = 10char c = 'a';
double d = 3.14;
类型 变量名 = 默认值

为什么要定义变量(为什么)

理解:

计算机是为了解决人计算能力不足的问题而诞生的。即,计算机是为了进行计算的。

而计算,就需要数据。

而要计算,任何一个时刻,不是所有的数据都要立马被计算。

如同:要吃饭,不是所有的饭菜都要立马被你吃掉。饭要一口一口吃,那么你还没有吃到的饭菜,就需要暂时放在盘子里。 这里的盘子,就如同变量,饭菜如同变量 里面的数据。

换句话说,为何需要变量?因为有数据需要暂时被保存起来,等待后续处理。

那么,为什么吃饭要盘子?我想吃一口菜了,直接去锅里找不行吗?当然行,但是效率低。 因为我们吃饭的地方,和做饭的地方,是比较"远"的。

变量定义的本质

我们现在已知:

  1. 程序运行,需要加载到内存中 ,变成进程。

  2. 程序计算,需要使用变量 那么,定义变量的本质:在内存中开辟一块空间,用来保存数据。(为何一定是内存:因为定义变量,也是程序逻辑的一部 分,程序已经被加载到内存)

变量声明的本质

我们目前只需要区分定义声明,即可,当我们学到extern的这个关键字,在细谈。

  1. 定义:开辟一个内存空间(只能有一次)
  2. 声明:告知编译器我有这个变量(通告)(声明可以多次)

结论:声明就是广而告之

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值