- 博客(181)
- 收藏
- 关注
原创 C语言:到底什么是链接,它起到了什么作用?
这样,不管在 func 之前增加或者减少了多少条指令导致 func 的地址发生了变化,汇编器在每次汇编程序的时候会重新计算 func 这个符号的地址,然后把所有使用到 func 的地方修正为新的地址,整个过程不需要人工参与。几十年以前,计算机刚刚诞生,人们编写程序时,将所有的代码都写在同一个源文件中,经过长期的积累,程序包含了数百万行的代码,以至于人们无法维护这个程序了。从本质上讲,C 语言中的函数就是一个代码块,当发生函数调用时,就会执行其他的代码块,这个过程就是通过跳转指令来完成的。
2025-02-17 09:11:52
254
原创 C语言:符号——链接的粘合剂
链接器所做的主要工作跟前面提到的“人工调整地址”本质上没有什么两样,只不过现代的高级语言拥有诸多的特性,使得编译器和链接器更为复杂,功能更为强大,但从原理上来讲,无非是找到符号的地址,或者把指令中使用到的地址加以修正。有了链接器,我们可以直接调用其他模块中的函数而无需知道它们的地址,因为在链接的时候,链接器会根据符号 func 自动去 module.c 模块查找 func 的地址,然后将 main.c 模块中所有使用到 func 的指令重新修正,让它们的目标地址成为真正的 func() 函数的地址。
2025-02-15 09:15:05
805
原创 C语言:强符号和弱符号
在 main.c 中,a 和 func 都是弱符号,在 module.c 中,a 和 func 都是强符号,强符号会覆盖弱符号,所以链接器最终会使用 module.c 中的符号,输出结果也印证了这一点。弱符号对于库来说十分有用,我们在开发库时,可以将某些符号定义为弱符号,这样就能够被用户定义的强符号覆盖,从而使得程序可以使用自定义版本的函数,增加了很大的灵活性。weak1 和 weak2 是弱符号,strong 和 main 是强符号,而 ext 既非强符号也非弱符号,它是一个对外部变量的引用(使用)
2025-02-15 09:14:50
327
原创 C语言:强引用和弱引用
弱引用和强引用非常利于程序的模块化开发,我们可以将程序的扩展模块定义为弱引用,当我们将扩展模块和程序链接在一起时,程序就可以正常使用;目前我们所看到的符号引用,在所有目标文件被链接成可执行文件时,它们的地址都要被找到,如果没有符号定义,链接器就会报符号未定义错误,这种被称为强引用(StrongReference)。链接器处理强引用和弱引用的过程几乎是一样的,只是对于未定义的弱引用,链接器不认为它是一个错误,一般默认其为 0(地址为 0),或者是一个特殊的值,以便程序代码能够识别。
2025-02-14 09:14:51
257
原创 C 语言模块化编程中的头文件
在项目开发中,我们可以将一组相关的变量和函数定义在一个 .c 文件中,并用一个同名的 .h 文件(头文件)进行声明,其他模块如果需要使用某个变量或函数,那么引入这个头文件就可以。这样做的另外一个好处是可以保护版权,我们在发布相关模块之前,可以将它们都编译成目标文件,或者打包成静态库,只要向用户提供头文件,用户就可以将这些模块链接到自己的程序中。.c 和.h 文件都是源文件,除了后缀不一样便于区分外和管理外,其他的都是相同的,在.c 中编写的代码同样也可以写在.h 中,包括函数定义、变量定义、预处理等。
2025-02-14 09:14:35
324
原创 细说 C 语言头文件的路径
需要注意的是,我们可以将./省略,此时默认从当前目录开始查找,例如#include "xyz.h"、#include"include/xyz.h"、#include "../xyz.h"、#include "../include/xyz.h"。以 Windows 为例,假设在 E:/cDemo/中有源文件 main.c 和头文件 xyz.h,那么在 main.c 中使用#include"./xyz.h"语句就可以引入 xyz.h,其中./表示当前目录,也即 E:/cDemo/
2025-02-13 09:15:49
661
原创 防止 C 语言头文件被重复包含
现在我们不妨换一种场景,假设 xyz1.h 中定义了类型 RYPE1,xyz2.h 中定义了类型 TYPE2,并且它们都包含了 stdio.h,如果主模块需要同时使用 TYPE1 和 TYPE2,就必须将 xyz1.h 和 xyz2.h 都包含进来,这样也会导致 stdio.h 被重复包含,并且无法回避,上面的方案解决不了问题。头文件包含命令 #include 的效果与直接复制粘贴头文件内容的效果是一样的,预处理器实际上也是这样做的,它会读取头文件的内容,然后输出到 #include 命令所在的位置。
2025-02-13 09:15:20
356
原创 C 语言 static 变量和函数
我们知道,全局变量和函数的作用域默认是整个程序,也就是所有的源文件,这给程序的模块化开发带来了很大方便,让我们能够在模块 A 中调用模块 B 中定义的变量和函数,而不用把所有的代码都集中到一个模块。静态局部变量虽然存储在全局数据区,但是它的作用域仅限于函数内部,func() 中的 n 在函数外无效,与main() 中的 n 不冲突,除了变量名一样,没有任何关系。下面我们通过一个实例来演示。注意:全局数据区的变量只能被初始化(定义)一次,以后只能改变它的值,不能再被初始化,即使有这样的语句,也无效。
2025-02-12 09:12:38
902
原创 C语言:目标文件和可执行文件里面都有什么?
常见的数据权限无外乎三种:只读(例如 .rodata 只读数据段)、读写(例如 .data 数据段)、读取和执行(例如 .text 代码段),我们将一块连续的、具有相同权限的数据称为一个 Segment,一个 Segment 由多个权限相同的 Section 构成。从广义上讲,目标文件与可执行文件的存储格式几乎是一样的,我们可以将它们看成是同一种类型的文件,在Windows 下,将它们统称为 PE 文件,在 Linux 下,将它们统称为 ELF 文件。链接的一个重要作用就是找到这些变量和函数的地址。
2025-02-12 09:12:16
1109
原创 那些被编译器隐藏了的过程
预处理和汇编的过程都比较简单,有了上面的介绍,相信大家很容易理解。而目标文件的结构、可执行文件的结构、链接的过程是我们要重点研究的,它能够让我们明白多文件编程以及模块化开发的原理,这是大型项目开发的基石。对于平常应用程序的开发,很少有人会关注编译和链接的过程,因为我们使用的工具一般都是流行的集成开发环境(IDE),比如 Visual Studio、Dev C++、C-Free 等。编译是整个程序构建的核心部分,也是最复杂的部分之一,涉及到的算法较多,我们并不打算深入讨论,有兴趣的读者请查看《编译原理》
2025-02-11 09:13:33
541
原创 从 extern 关键字开始谈 C 语言多文件编程
其实不然,头文件中包含的都是函数声明,而不是函数定义,函数定义都在系统库中,只有头文件没有系统库在链接时就会报错,程序根本不能运行。在前面的教程中,我们都是将所有的代码写到一个源文件里面,对于小程序,代码不过几百行,这或许无可厚非,但当程序膨胀代码到几千行甚至上万行后,就应该考虑将代码分散到多个文件中,否则代码的阅读和维护将成为一件痛苦的事情。extern 是“外部”的意思,很多教材讲到,extern 用来声明一个外部(其他文件中)的变量或函数,也就是说,变量或函数的定义在其他文件中。
2025-02-11 09:10:59
591
原创 malloc 函数背后的实现原理——内存池
相对于栈而言,堆这片内存面临着一个稍微复杂的行为模式:在任意时刻,程序可能发出请求,要么申请一段内存,要么释放一段已经申请过的内存,而且申请的大小从几个字节到几个 GB 都有可能,我们不能假设程序一次申请多少堆空间,因此,堆的管理显得较为复杂。内存池的研究重点不是向操作系统申请内存,而是对已申请到的内存的管理,这涉及到非常复杂的算法,是一个永远也研究不完的课题,除了 C 标准库自带的 malloc(),还有一些第三方的实现,比如 Goolge 的 tcmalloc和 jemalloc。
2025-02-10 09:17:10
802
原创 C 语言内存泄露(内存丢失)
这就导致了一个问题,第一次分配的 100 字节的内存没有指针指向它了,而且我们也不知道这块内存的地址,所以就再也无法找回了,也没法释放了,这块内存就成了垃圾内存,虽然毫无用处,但依然占用资源,唯一的办法就是等程序运行结束后由操作系统回收。free() 函数的用处在于实时地回收内存,如果程序很简单,程序结束之前也不会使用过多的内存,不会降低系统的性能,那么也可以不用写 free() 函数。这样的操作没有意义,因为没有指针指向分配的内存,无法使用,而且无法通过 free() 释放掉,造成了内存泄露。
2025-02-10 09:16:41
336
原创 C 语言变量的存储类别和生存期
静态局部变量虽然存储在静态数据区,但是它的作用域仅限于定义它的代码块,sum() 中的 result 在函数外无效,与 main() 中的 result 不冲突,除了变量名一样,没有任何关系。通俗地讲,生存期指的是在程序运行过程中,变量从创建到销毁的一段时间,生存期的长短取决于变量的存储类别,也就是它所在的内存区域。注意:静态数据区的变量只能初始化(定义)一次,以后只能改变它的值,不能再被初始化,即使有这样的语句,也无效。我们知道,变量是有数据类型的,用以说明它占用多大的内存空间,可以进行什么样的操作。
2025-02-09 09:59:31
469
原创 C 语言野指针以及非法内存操作
这是因为,freed() 只是释放掉了动态分配的内存,但并未改变 str 的值,str 的值不是 NULL,它仍然指向被释放掉的内存,所以会执行 if 语句里面的 puts() 函数。arr 数组在栈上分配内存,字符串"hello world"就存储在这里,func() 函数运行结束后,这块内存被释放掉,但是函数外部的 pstr 仍然指向这里,所以执行 puts(pstr);当然,如果足够幸运的话,str 也可能恰好指向一段分配好的、并且有读写权限的内存,程序就运行成功了,但这是小概率事件,一般不会发生。
2025-02-09 09:59:10
603
原创 一篇文章带你轻松解决Windows系统右键新建Word、Excel、PPT功能缺失的问题
在注册表左侧第一项HKEY_CLASSES_ROOT中,选择我们需要开启新建的文件类型,如Excel文件选择.xlsx,Word文件选择.docx,PPT文件选择.pptx。我这里演示Excel的右键缺失修复,选择.xlsx,在默认处我们已经可以分析到问题原因,是因为我安装了腾讯文档软件,导致我的.xlsx文件默认应用都变成了腾讯文档导致的。此时双击默认,修改数值为对应数值即可,如下所示,修改完后刷新桌面,如未显示重启电脑即可。
2025-02-08 11:05:08
444
原创 C语言动态内存分配
程序启动时会为栈区分配一块大小适当的内存,对于一般的函数调用这已经足够了,函数进栈出栈只是 ebp、esp 寄存器指向的变换,或者是向已有的内存中写入数据,不涉及内存的分配和释放。这称为静态内存分配。注意:calloc() 函数是对 malloc() 函数的简单封装,参数不同,使用时务必小心,第一参数是第二参数的单元个数,第二参数是单位的字节数。注意:分配内存在动态存储区(堆区),手动分配,手动释放,申请时空间可能有也可能没有,需要自行判断,由于返回的是 void*,建议手动强制类型转换。
2025-02-08 10:33:18
821
原创 栈溢出攻击的原理是什么?
局部数组也是在栈上分配内存,当输入"12345678901234567890" 时,会发生数组溢出,占用“4 字节空白内存”、“old ebp”和“返回地址”所在的内存,并将原有的数据覆盖掉,这样当 main() 函数执行完成后,会取得一个错误的返回地址,该地址上的指令是不确定的,或者根本就没有指令,所以程序在返回时出错。C 语言不会对数组溢出做检测,这是一个典型的由于数组溢出导致覆盖了函数返回地址的例子,我们将这样的错误称为“栈溢出错误”。
2025-02-07 16:45:46
428
原创 C语言:用一个实例来深入剖析函数进栈出栈的过程
首先将原来 ebp 寄存器的值压入栈中(也即图中的 oldebp),并将 esp 的值赋给 ebp,这样 ebp 就从 main() 函数的栈底指向了 func() 函数的栈底,完成了函数栈的切换。经过上面的分析可以发现,函数出栈只是在增加 esp 寄存器的值,使它指向上一个数据,并没有销毁之前的数据。为局部变量分配内存时,仅仅是将 esp 的值减去一个整数,预留出足够的空白内存,不同的编译器在不同的模式下会对这片空白内存进行不同的处理,可能会初始化为一个固定的值,也可能不进行初始化。
2025-02-07 16:44:19
909
原创 函数调用管理(Calling Convention)
对于 main() 调用 funcB(),我们称 main() 是调用方,funcB() 是被调用方;同理,对于 funcB() 调用 funcA(),funcB() 是调用方,funcA() 是被调用方。以 funcB() 为例,假设 main() 函数先将 19.9 入栈,后将 28.5 入栈,但是 funcB() 在使用这些实参时却认为28.5 先入栈,19.9 后入栈,那么就一定会产生混乱,误以为 19.9 是传递给 b、28.5 是传递给 a 的。
2025-01-23 10:19:33
392
原创 C语言:用户模式和内核模式
但是用户程序是非常不安全的,内核对用户程序也是充分不信任的,当程序调用内核接口时,内核要做各种校验,以防止出错。内核空间存放的是操作系统内核代码和数据,是被所有程序共享的,在程序中修改内核空间中的数据不仅会影响操作系统本身的稳定性,还会影响其他程序,这是非常危险的行为,所以操作系统禁止用户程序直接访问内核空间。要想访问内核空间,必须借助操作系统提供的 API 函数,执行内核提供的代码,让内核自己来访问,这样才能保证内核空间的数据不会被随意修改,才能保证操作系统本身和其他程序的稳定性。
2025-01-23 10:18:09
378
原创 C语言:分页机制如何实现
现在硬件很便宜了,内存容量大了,很多电脑都配备 4G 或 8G 的内存,页表数组占用 4M 内存或许不觉得多,但在 32 位系统刚刚发布的时候,内存还是很紧缺的资源,很多电脑才配备 100M 甚至几十兆的内存,4M 内存就显得有点大了,所以还得对上面的方案进行改进,压缩页表数组所占用的内存。在极少数的情况下,程序占用的内存非常大,布满了 4G 的虚拟地址空间,这样小页表的数量可能接近甚至等于1024,再加上页目录占用的存储空间,总共是 4MB+4KB,比上面使用一级页表的方案仅仅多出 4KB 的内存。
2025-01-21 09:26:16
815
原创 C语言:内存分页机制,完成虚拟地址映射
Program 1 的 VP2、VP3 不在内存中,但是当进程需要用到这两个页的时候,硬件会捕获到这个消息,就是所谓的页错误(Page Fault),然后操作系统接管进程,负责将 VP2 和 PV3 从磁盘中读取出来并且装入内存,然后将内存中的这两个页与 VP2、VP3 之间建立映射关系。物理内存也是同样的分法。这里,我们把虚拟空间的页叫做虚拟页(VP,Virtual Page),把物理内存中的页叫做物理页(PP,PhysicalPage),把磁盘中的页叫做磁盘页(DP,Disk Page)。
2025-01-21 09:23:28
751
原创 C语言:虚拟地址空间及编译模式
所谓虚拟地址空间,就是程序可以使用的虚拟地址的有效范围。虚拟地址和物理地址的映射关系由操作系统决定,相应地,虚拟地址空间的大小也由操作系统决定,但还会受到编译模式的影响。这节我们先讲解 CPU,再讲解编译模式,让大家了解编译器是如何配合 CPU 来提高程序运行速度的。CPU 是计算机的核心,决定了计算机的数据处理能力和寻址能力,也即决定了计算机的性能。
2025-01-13 16:58:35
1030
原创 C语言:一篇内容带你了解虚拟内存
代码中的 a、b 是全局变量,它们的内存地址在链接时就已经决定了,以后再也不能改变,该程序无论在何时运行,结果都是一样的。那么问题来了,如果物理内存中的这两个地址被其他程序占用了怎么办,我们的程序岂不是无法运行了?幸运的是,这些内存地址都是假的,不是真实的物理内存地址,而是虚拟地址。虚拟地址通过 CPU 的转换才能对应到物理地址,而且每次程序运行时,操作系统都会重新安排虚拟地址和物理地址的对应关系,哪一段物理内存空闲就使用哪一段。
2025-01-13 16:56:55
795
原创 C语言:内存中程序是如何运行的
程序是保存在硬盘中的,要载入内存才能运行,CPU 也被设计为只能从内存中读取数据和指令。对于 CPU 来说,内存仅仅是一个存放指令和数据的地方,并不能在内存中完成计算功能,例如要计算 a = b +c,必须将 a、b、c 都读取到 CPU 内部才能进行加法运算。为了了解具体的运算过程,我们不妨先来看一下CPU 的结构。CPU 是一个复杂的计算机部件,它内部又包含很多小零件,如下图所示:运算单元是 CPU 的大脑,负责加减乘除、比较、位移等运算工作,每种运算都有对应的电路支持,速度很快。
2025-01-08 09:09:32
1502
原创 C语言:调试的总结和技巧
接下来,我们来了解一下调试标记。此时,我们就应该考虑问题是否出现在之前的函数上了,可能因为偶然性,我们第一次测试函数的时候并没有发现其错误,导致范围锁定产生偏差,此时我们需要再次耐心的对所有未排除嫌疑的进行调试,直至再次找到出错的函数。当我们运行我们编写的程序发现运行结果与我们预想的不同的时候,我们可以先用即时窗口,使用一些比较简单的数据来测试我们的各个函数运行结果是否符合我们的预期,如果都符合的话,我们可以使用程序中产生的一些比较复杂的数据来进一步测试我们的各个函数,直至找到可能导致错误的函数。
2025-01-08 09:07:25
913
原创 C语言:assert断言函数
很明显,这样做是不可以的。我们看到,只要我们定义了 NDEBUG 宏,assert 就会失效,而 Visual Studio 的默认的发布版程序编译参数中定义了 NDEBUG 宏,所以我们不用额外定义,但是在其他编译器中,我们在发布程序的时候就必须在包含assert.h 头文件前定义 NDEBUG 宏,避免 assert 生效,否则总是让用户看到“程序已经停止运行,正在寻找解决方案 . . .”的 Windows 系统对话框可就不妙了。在我们的实际使用过程中,我们需要注意一些使用 assert 的问题。
2025-01-06 09:22:42
698
原创 C语言:单步调试与即时窗口的使用
在实际开发中,常常会出现这样的情况,我们可以大致把出现问题的代码锁定在一定范围内,但无法确定到底是哪条语句出现了问题,该怎么办呢?按照前面的思路,必须要在所有代码行前面设置断点,让代码一个断点一个断点地执行。这种方案确实可行,但很麻烦,也不专业,这节我们就来介绍一种更加便捷的调试技巧——单步调试。所谓单步调试,就是让代码一步一步地执行。
2025-01-06 09:18:50
822
原创 C语言:调试的概念和调试器的选择
在调试的过程中,我们可以监控程序的每一个细节,包括变量的值、函数的调用过程、内存中数据、线程的调度等,从而发现隐藏的错误或者低效的代码。我敢保证,每个人都会遇到逻辑错误,而且会经常遇到,初学者更是错的离谱,所以,必须掌握调试技能,没有选择的余地,没有学会调试就是没有学会编程!严格来说,调试器遇到断点时会把程序暂时挂起,让程序进入一种特殊的状态——中断状态,这种状态下操作系统不会终止程序的执行,也不会清除与程序相关的元素,比如变量、函数等,它们在内存中的位置不会发生变化。双击变量的值,可以进行修改。
2024-12-31 17:10:58
1061
原创 C语言:获取文件大小(长度)、插入、删除、更改文件内容
实际开发中,有时候需要先获取文件大小再进行下一步操作。C 语言没有提供获取文件大小的函数,要想实现该功能,必须自己编写函数。注意:fp 要以二进制方式打开,如果以文本方式打开,函数的返回值可能没有意义。先使用 fseek() 将文件内部指针定位到文件末尾,再使用 ftell() 返回内部指针距离文件开头的字节数,这个返回值就等于文件的大小。这段代码并不健壮,它移动了文件内部指针,可能会导致接下来的文件操作错误。fread() 函数将永远读取不到内容。
2024-12-25 11:16:48
1105
原创 FILE 结构体以及缓冲区深入探讨
如果我们通过 setbuf()或 setvbuf()函数将缓冲区设置 10 个字节的大小,而我们从键盘输入了 20 个字节大小的数据,这样我们输入的前 10 个数据会放在缓冲区中,因为我们设置的缓冲区的大小只能够装下 10 个字节大小的数据,装不下 20 个字节大小的数据。上面的箭头表示的区域就相当是一个输入流,红色的地方相当于一个开关,这个开关可以控制往深绿色区域(标注的是缓冲区)里放进去的数据,输入 20 个字节的数据只往缓冲区中放进去了 10 个字节,剩下的 10 个字节的数据就被停留在了输入流里!
2024-12-24 10:40:45
880
原创 C语言:随机读写文件、实现文件复制功能
前面介绍的文件读写函数都是顺序读写,即读写文件只能从头开始,依次读写各个数据。但在实际开发中经常需要读写文件的中间部分,要解决这个问题,就得先移动文件内部的位置指针,再进行读写。这种读写方式称为随机读写,也就是说从文件的任意位置开始读写。实现随机读写的关键是要按要求移动位置指针,这称为文件的定位。文件定位函数 rewind 和 fseek移动文件内部位置指针的函数主要有两个,即 rewind() 和 fseek()。参数说明:fp 为文件指针,也就是被移动的文件。
2024-12-24 10:38:44
709
原创 C语言:以数据块的形式读写文件
fgets() 有局限性,每次最多只能从文件中读取一行内容,因为 fgets() 遇到换行符就结束读取。如果希望读取多行内容,需要使用 fread() 函数;相应地写入函数为 fwrite()。fread() 函数用来从指定文件中读取块数据。所谓块数据,也就是若干个字节的数据,可以是一个字符,可以是一个字符串,可以是多行数据,并没有什么限制。fread() 的原型为:对参数的说明: ptr 为内存区块的指针,它可以是数组、变量、结构体等。
2024-12-20 14:14:33
534
原创 C语言:以字符形式读写文件
在 C 语言中,读写文件比较灵活,既可以每次读写一个字符,也可以读写一个字符串,甚至是任意字节的数据(数据块)。本节介绍以字符形式读写文件。以字符形式读写文件时,每次可以从文件中读取一个字符,或者向文件中写入一个字符。主要使用两个函数,分别是fgetc() 和 fputc()。
2024-12-18 11:53:29
1155
原创 C语言中文件是什么?文件文本和二进制文件的区别
我们对文件的概念已经非常熟悉了,比如常见的 Word 文档、txt 文件、源文件等。文件是数据源的一种,最主要的作用是保存数据。在操作系统中,为了统一对各种硬件的操作,简化接口,不同的硬件设备也都被看成一个文件。对这些文件的操作,等同于对磁盘上普通文件的操作。例如:通常把显示器称为标准输出文件,printf 就是向这个文件输出数据;通常把键盘称为标准输入文件,scanf 就是从这个文件读取数据。我们不去探讨硬件设备是如何被映射成文件的,大家只需要记住,在 C 语言中硬件设备可以看成文件,有些输入输出函数不需
2024-12-18 11:53:15
846
原创 C语言打开文件:fopen函数的用法
在 C 语言中,操作文件之前必须先打开文件;所谓“打开文件”,就是让程序和文件建立连接的过程。打开文件之后,程序可以得到文件的相关信息,例如大小、类型、权限、创建者、更新时间等。在后续读写文件的过程中,程序还可以记录当前读写到了哪个位置,下次可以在此基础上继续操作。标准输入文件 stdin(表示键盘)、标准输出文件 stdout(表示显示器)、标准错误文件 stderr(表示显示器)是由系统打开的,可直接使用。filename 为文件名(包括文件路径),mode 为打开方式,它们都是字符串。
2024-12-16 14:08:37
1127
原创 C语言:随机数生成rand()和srand()
在实际编程中,我们经常需要生成随机数,例如,贪吃蛇游戏中在随机的位置出现食物,扑克牌游戏中随机发牌。void 表示不需要传递参数。C 语言中还有一个 random() 函数可以获取随机数,但是 random() 不是标准函数,不能在 VC/VS 等编译器通过,所以比较少用。RAND_MAX 是 头文件中的一个宏,它用来指明 rand() 所能返回的随机数的最大值。C 语言标准并没有规定 RAND_MAX 的具体数值,只是规定它的值至少为 32767。
2024-12-16 14:03:18
880
原创 C语言:const的用法
有时候我们希望定义这样一种变量,它的值不能被改变,在整个作用域中都保持固定。例如,用一个变量来表示班级的最大人数,或者表示缓冲区的大小。我们经常将 const 变量称为常量(Constant)。但我们通常采用第一种方式,不采用第二种方式。另外建议将常量名的首字母大写,以提醒程序员这是个常量。由于常量一旦被创建后其值就不能再改变,所以常量必须在定义的同时赋值(初始化),后面的任何赋值行为都将引发错误。运行结果: 100, 90, 80。
2024-12-14 16:48:00
1025
原创 C语言:结构体共用体
共用体有时也被称为联合或者联合体,这也是 Union 这个单词的本意。结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。结构体占用的内存大于等于所有成员占用内存的总和(成员之间可能会有缝隙)共用体占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。
2024-12-13 11:13:16
430
AI大模型-DeepSeek V3搭建个人知识库教程
2025-02-11
AI大模型-DeepSeek教程从入门到精通
2025-02-11
ipmsg飞鸽传输项目源码与软件需求说明书.zip
2024-09-06
《Linux操作系统命令全攻略》图解手册
2024-09-06
《C++ STL标准模板库完全指南》详解与实战案例
2024-09-06
《150款专业单页简历模板》精选合集
2024-09-06
《嵌入式面试Linux核心知识点》全面解析
2024-09-06
F103-指南者-原理图.zip
2024-08-31
STM32固件库使用手册的中文翻译版.zip
2024-08-31
掌握UDP网络编程:嵌入式系统工程师的高效通信指南
2024-08-24
精通Socket编程:嵌入式系统工程师的TCP/IP网络通信指南
2024-08-24
嵌入式系统工程师必读:全面深入的计算机网络基础与TCP/IP协议解析
2024-08-24
嵌入式系统优化:线程管理与同步互斥机制解析
2024-08-24
嵌入式系统开发:深入理解信号机制及其在进程通信中的应用
2024-08-24
掌握嵌入式系统中的高效IPC:消息队列与共享内存深度解析
2024-08-24
嵌入式系统中的进程间通信:深入管道与命名管道
2024-08-24
深入解析嵌入式系统中的进程管理
2024-08-24
掌握系统调用与标准I/O:Linux系统编程精要
2024-08-24
Linux编程自动化:精通Make工具与Makefile
2024-08-24
深入Linux编程核心:GCC与GDB工具详解
2024-08-24
掌握Linux编程核心:Shell脚本与工具使用指南
2024-08-24
深入探索Linux世界:《Linux下编程工具(概述、目录结构)》精粹指南
2024-08-24
精通Linux命令行:《Linux下编程工具(Linux命令、vi)》教程全解析
2024-08-24
掌握Linux开发环境搭建:Ubuntu系统安装与配置全指南
2024-08-24
深入探索操作系统的演变:从无到有,Linux的崛起与未来
2024-08-23
学生信息管理系统项目答辩PPT
2024-08-23
学生信息管理系统的设计与实现
2024-08-22
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人