
C语言进阶之道
文章平均质量分 90
C语言进阶之道
几度春风里
几度春风里,看花谢花开,含羞的程序员,惹人爱!
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
C缺陷与陷阱 — 1 数据类型与关键字
类似地,当函数在另一个文件中定义时,可以使用extern在需要调用该函数的文件中声明它。不过,对于函数来说,extern是隐含的,即使不显式声明extern,编译器也会假定函数是在其他地方定义的,除非它同时被声明和定义在同一个文件中。:在多个文件中共享全局变量时,通常在一个文件中定义变量(不加extern),而在其他需要使用该变量的文件中声明它(使用extern)。:在文件作用域(即全局作用域)中使用static关键字声明变量,该变量只在定义它的文件内部可见,这有助于避免不同文件之间的命名冲突。原创 2024-11-17 09:54:52 · 724 阅读 · 0 评论 -
C缺陷与陷阱 — 2 运算符进阶
和 ,)存在规定的求值顺序。:用于表示单个字符常量,例如 'A' 表示大写字母A,'0' 表示数字0,单引号内的字符可以是任何有效的字符,包括字母、数字、空格、标点符号等,如果单引号内包含多于一个字符,或者没有字符,编译器会报错。在C语言中,按位与运算符&和按位或运算符|是位操作符号,&&和 || 是逻辑运算符号,在实际编程中,位运算符通常用于底层硬件操作或位字段的设置和清除,而逻辑运算符则用于控制程序的流程。可能本意是用x除以z所指向的值,把所得的商再赋给y,将上面的语句重写如下才是所表示的原意。原创 2024-11-17 10:09:59 · 693 阅读 · 0 评论 -
C缺陷与陷阱 — 3 深入理解表达式
成员函数 task_start_fn 的地址和 p++ 的值都是在调用之前计算的,但是它们的计算顺序是不确定的。这意味着 p++ 可能会在 task_start_fn 的地址被计算之前或之后执行,导致 task_start_fn 可能被调用时使用的是 p 的原始值或增加后的值,这是不可预测的。因此,b[i] 的运算会使用 i 的当前值,然后 i 的值会增加 1。编译器可能先计算fun1(),也可能先计算fun2(),由于x的结果依赖于函数fun1()、fun2()的计算次序,则上面的代码存在问题。原创 2024-12-10 22:14:53 · 850 阅读 · 0 评论 -
C缺陷与陷阱 — 4 深入理解声明与定义
typedef用于为已存在的类型定义一个新的名字,它是一个编译时的指令,由编译器处理,typedef定义的类型别名在编译时会进行类型检查。描述对象的类型,用于指代其他地方定义的对象,由于并未在声明中为数组分配内存,所以并不需要提供关于数组长度的信息。在C语言中,声明的基本格式遵循一种相对固定的结构,尽管根据声明的具体内容(如变量、数组、函数、指针等),格式会有所变化。2)在连续几个变量的声明中,用typedef定义的类型能够保证声明中所有的变量为为同一种类型,而用#define定义的类型则无法保证。原创 2024-11-17 10:27:53 · 685 阅读 · 0 评论 -
C缺陷与陷阱 — 5 深入理解函数与库函数
遗憾的是,事实总难遂人所愿,为了保持与过去不能同时进行读写操作的程序的向下兼容性,一个输入操作不能随后直接紧跟一个输出操作,反之亦然。因为()结合优先级高于*,*pf()也就是*(pf()),pf是一个函数,该函数的返回值类型为指向浮点数的指针。signal 函数允许程序为特定的信号指定一个信号处理函数,当进程接收到该信号时,将调用指定的函数。出错原因在于,在库函数调用没有失败的情况下,并没有强制要求库函数一定要设置errno为0,这样ermo的值就可能是前一个执行失败的库函数设置的值。原创 2024-11-17 11:53:41 · 724 阅读 · 0 评论 -
C缺陷与陷阱 — 6 指针与数组进阶
在堆上malloc或者new出来的地址空间,如果已经free或delete,那么此时堆上的内存已经被释放,但是指向该内存的指针如果没有人为的修改过,那么指针还会继续指向这段堆上已经被释放的内存,这时还通过该指针去访问堆上的内存,就会造成不可预知的结果,给程序带来隐患。这段实现可能存在一些问题,首先我们并不知道为r所指向的位置,此外r并没有分配足够的内存,使用strcy和strcat将会导致缓冲区溢出,r应该指向一个足够大的内存区域,以存储s和t字符串的复制或连接结果。用数组形式的记法经常会起到误导作用。原创 2024-11-17 10:45:03 · 982 阅读 · 0 评论 -
C缺陷与陷阱 — 7 内存管理进阶
同时释放一块内存的一部分是不允许的,动态分配的内存必须整块一起释放。这些错误包括对NULL指针进行解引用操作、对分配的内存进行操作时越过边界、释放并非动态分配的内存、试图释放一块动态分配的内存的一部分以及一块动态内存被释放之后被继续使用。是指程序中已分配的内存空间,在不再使用之后没有被正确释放或无法被再次使用,导致随着程序的运行,可用内存空间逐渐减少,最终可能耗尽系统内存,造成程序崩溃或系统性能下降。用于在堆(heap)上动态分配指定数量的字节,malloc 分配的内存是未初始化的,其内容是不确定的。原创 2024-11-17 11:01:25 · 772 阅读 · 0 评论 -
C缺陷与陷阱 — 8 编译与链接
静态链接在生成可执行文件时,会把程序所用到的函数库(比如标准 C 库、数学库等)中相关目标文件的代码和数据全部复制到可执行文件里面,即便它可能只调用了库中的少数几个函数,而动态链接则不同,动态链接的可执行文件中只是包含了对相应动态库中函数和变量等的引用信息,真正的函数库代码并不嵌入到可执行文件里。在这个过程中,像 printf 这类库符号所在的动态库(例如 libc.so 等)会在运行时被加载到程序的虚拟地址空间,使得程序可以找到并执行相应的函数,并且多个链接在一起的文件都可以访问到这些动态库中的符号。原创 2024-12-15 21:31:04 · 1161 阅读 · 0 评论 -
C缺陷与陷阱 — 9 可移植性缺陷
这是会失败的,因为在将字符c转换为无符号整数时,c将首先被转换为int型整数,而此时可能得到非预期的结果。如果要满足第2条性质,答案应该是-1,但如果是这样,余数就必定是-1,这样第3条性质就无法满足。这样,性质1和性质2就可以得到满足。然而,C语言的定义只保证了性质1,以及当a>=0且b>0时,保证 |r|=0.后面部分的保证与性质2或者性质3比较起来,限制性要弱得多。例如,对于32位的整数,n原创 2024-11-17 12:05:03 · 1223 阅读 · 0 评论 -
代码整洁之道 — 1 代码总体原则
例如,一个简单的学生信息管理系统,将学生结构体和相关操作函数分开,模块之间接口要清晰,比如上述inputStudentInfo函数明确接收一个Student结构体指针作为输入,用来填充学生信息,displayStudentInfo函数接收一个Student结构体来展示其信息。写的代码越 多,意味着出错的地方越多,也就意味着代码的可靠性越低。例如,在进行位操作时,要确保代码在不同的字节序(大端序和小端序)的机器上都能正确运行。并遵循统一的命名风格,常见的是驼峰命名法或者下划线命名法,整个项目保持一致。原创 2024-12-15 10:41:10 · 568 阅读 · 0 评论 -
代码整洁之道 — 1 命名规范
1.1 不同数据类型命名规范编程中不同数据的命名规范提高了代码的可读性和一致性。例如,常量和宏定义使用全大写字母,变量和函数采用小驼峰式,而结构体和枚举类型名则使用大驼峰式,这样的区分有助于识别代码中的不同元素。类型规范示例常量名全大写,单词间用下划线分隔变量名小驼峰式(首单词小写,后续单词首字母大写)函数名小驼峰式(同变量名)结构体名大驼峰式(所有单词首字母大写)联合体名大驼峰式(同结构体名)枚举类型名大驼峰式(同结构体名)Weekday宏定义。原创 2024-10-01 12:30:13 · 1141 阅读 · 0 评论 -
代码整洁之道 — 2 函数规范
因此,在保持函数简短的情况下,偶尔使用return、break或continue语句是可以接受的,它们可以提高代码的表达力。为了提高代码的清晰度,我们应该按照自顶向下的顺序组织函数,每个函数都应该调用下一个抽象层级的函数,形成清晰的阅读路径。函数名和参数应该形成清晰的动词/名词对,这有助于解释函数的意图和参数的顺序,关键字形式的函数名可以减少记忆参数顺序的负担。避免使用布尔值作为标识参数,因为这会增加函数的复杂性,如果必须使用,应该考虑将函数拆分为两个或更多函数。2 switch语句。原创 2024-10-01 17:32:50 · 574 阅读 · 0 评论 -
代码整洁之道 — 3 头文件规范
就我们的产品来说,依赖的方向应该是:产品依赖于平台,平台依赖于标准库。头文件循环依赖,指a.h包含b.h,b.h包含c.h,c.h包含a.h之类导致任何一个头文件修改,都 导致所有包含了a.h/b.h/c.h的代码全部重新编译一遍。很多系统中头文件包含关系复杂,开发人员为了省事起见,可能不会去一一钻研,直接包含一切想到的头文件,甚至有些产品干脆发布了一个god.h,其中包含了所有头文件,然后发布给各个项目组使用,这种只图一时省事的做法,导致整个系统的编译时间进一步恶化,并对后来人的维护造成了巨大的麻烦。原创 2024-12-15 11:48:19 · 1617 阅读 · 0 评论 -
代码整洁之道 — 4 变量与常量规范
首先,定义指针常量时会有点不同。这里期望 DOUBLE(num) 能将 num 的值翻倍,但由于宏替换后变成了 (3 + 4 * 2),按照 C 语言运算优先级,先计算乘法再计算加法,得到的结果是 11,而不是预期的 14。说明:系统启动阶段,使用全局变量前,要考虑到该全局变量在什么时候初始化,使用全局变量和初 始化全局变量,两者之间的时序关系,谁先谁后,一定要分析清楚,不然后果往往是低级而又灾难性 的。例如,对于16位的整数0x1234,在大端序存储中,0x12存储在低地址处,0x34存储在高地址处。原创 2024-12-15 11:55:36 · 602 阅读 · 0 评论 -
代码整洁之道 — 6 注释规范
在编写代码时,注释的质量至关重要。:可警告其他程序员可能出现的后果,虽现在有其他替代做法(如 JUnit4 里的@Ignore属性),但以前常用注释方式,且在合适场景下注释还是有用的,能避免一些不当做法。TODO只是暂时性的提醒注释,因此,定期检查这些注释,并删除那些已经不再需要的,是一个很好的习惯。这种注释风格在没有源代码控制系统(如git)的年代可能有一定的价值,但在现代开发实践中,它被认为是不必要的,甚至有害的。带有少量注释的整洁而有表达力的代码,要比带有大量注释的零碎而复杂的代码像样得多。原创 2024-12-15 12:13:55 · 2446 阅读 · 0 评论