IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

标签:C语言

共 40 篇相关文章

IT 累计浏览 56

一个简单的 A star 寻路算法实现

这篇讲的是一个极简A*寻路算法的实现,作者从实用角度出发,重新设计了一套C语言接口,核心特点是与地图数据结构完全解耦,方便移植到不同场景。 实现上最巧妙的是用单向链表替代了传统A*中复杂的优先队列,同时把所有寻路数据压进一块平坦内存,这样既避免了算法执行中的内存分配,又天然兼容多线程环境。底层数据结构是一个闭散列哈希表,作者用一个自增的version值巧妙实现了O(1)复杂度的表重置,大幅降低重复寻路时的初始化开销。 考虑到实际地图规模,算法内置了安全阀:当哈希表使用率超过一半时自动中止,但会返回已找到的离目标最近的中途点,用户可多次调用拼接完整路径。作者还贴心地提供了可视化函数,能将哈希表内部状态输出为灰度图,方便调试。 虽然代码刚写好还未充分测试,但作者追求的“接口简单、数据结构通用、内存开销固定”的设计目标清晰明确,适合那些需要轻量、易集成寻路功能的项目。

IT 累计浏览 2,295

PHP扩展内如何定义类、方法?

这篇讲的是PHP扩展开发中的核心操作——如何在C语言层面定义一个PHP类。作者从PHP类的底层数据结构`zend_class_entry`入手,解释了这个结构体如何容纳类名、方法表、属性以及各类魔术方法。 文章的核心思路是,首先声明一个类入口指针(通常命名为`xxx_ce`),然后在模块初始化阶段(`PHP_MINIT_FUNCTION`)完成类的注册。具体步骤包括:声明方法实现、通过`zend_function_entry`数组绑定方法到类,最后调用`INIT_CLASS_ENTRY`和`zend_register_internal_class`完成类的注册。作者还分享了一个实用技巧:把类入口定义放在文件靠前位置,便于后续代码引用。 整篇文章从底层结构到具体实现代码,完整演示了从零开始在PHP扩展中“创建”一个类的过程。对于需要编写PHP扩展的开发者来说,这清晰地揭示了PHP面向对象特性在底层的实现起点。

IT 累计浏览 3,001

一起空指针引发的程序问题的排查过程

这篇讲的是一个空指针引发的程序崩溃案例,作者从一次测试中的突发崩溃出发,详细还原了完整的排查过程。 问题现象是程序在某个功能函数中崩溃,初步日志显示崩溃发生在处理数据库超时异常的流程中。通过分析堆栈和参数,排查迅速聚焦到崩溃行的具体代码:一个指针变量 `pReq` 被用来访问结构体成员,但该指针本身可能有问题。 根源在于一个细节:在向数据库发送消息时,传入的 `para` 参数是空指针且长度为0。这导致在后续复用存储空间的 `DlgBuf` 中,对应的 `para` 字段未被赋值,依然是初始化时的空指针。当数据库无应答触发超时处理时,程序用同一个序列号去取这个空指针并试图解引用,自然就崩溃了。作者通过修改调用代码,传入有效的结构体指针进行验证,问题得以解决。 这个案例很典型,它揭示了在C语言中对指针“先检查、后使用”的必要性,尤其是在异常处理和超时等非主流程路径上。文章最后的总结经验——对重要指针务必校验非空,将其视为一种异常保护手段——对处理类似底层内存问题很有参考价值。

IT 累计浏览 3,422

C语言的整型溢出问题

这篇讲的是C语言中一个常被忽视但极其危险的安全陷阱:整型溢出。作者从“无符号整型溢出有定义(模运算),而有符号整型溢出是未定义行为”这个核心区别出发,拆解了问题的根源。 文章的重点在于揭示溢出带来的真实危害,并用四个具体示例生动说明。例如,一个简单的`while`循环可能因`short`溢出而变成死循环;一次看似安全的内存拷贝检查,会因`int`到`size_t`的隐式类型转换而被绕过,导致缓冲区溢出。更严重的案例直接关联到OpenSSL的Heartbleed漏洞,展示了如何通过精心构造的输入,让`malloc`分配的内存远小于预期,从而引发远程代码执行。 作者还特别提醒了编译器优化带来的“反直觉”行为:编译器在`-O2`等优化级别下,会假定有符号整型不会溢出,从而直接删除你手写的溢出检查代码。这意味着,那些在调试版本下有效的保护措施,可能在发布版本中完全失效,这使得问题更加隐蔽和致命。 整篇文章就像一份简洁的安全编码警示录,它没有停留在理论定义,而是通过剖析编译器行为和真实漏洞,提醒开发者在处理整数时必须如履薄冰,尤其是在涉及内存操作和用户输入的场景中。

IT 累计浏览 4,341

& * # 这三个是什么符号?

这篇讲的是,很多国内程序员都习惯用中文叫那些常见符号——“and符”、“星号”、“井号”,但在国际技术交流中,它们却有另一个名字。作者从一次听国外公开课“彻底懵了”的经历出发,点出了这个细微却影响交流的认知差异。 文章核心就在于“翻译”这三个符号在技术语境下的真正发音和背景:& 其实是 ampersand,它的含义就是“and”;* 的名字是 asterisk,常见于表示脚注;而 # 的英文名是 hash,在英语中既可以表示数字序号(如地址#18),在美国还用作重量单位“磅”(如2# sugar,约两斤糖)。 这篇文章提醒我们,在阅读英文技术文档、观看国际公开课时,理解这些符号的“本名”非常关键。它不光是一个冷知识,更是帮助我们流畅获取一手技术信息的一个小钥匙。

IT 累计浏览 3,886

深入剖析 redis RDB 持久化策略

这篇讲的是 Redis RDB 持久化的底层实现。作者从 RDB 与 AOF 的基本概念切入,随后迅速深入核心,剖析了负责持久化 IO 操作的关键数据结构 `struct rio`。 文章的亮点在于对 `rio` 结构的拆解。它巧妙地通过函数指针(如 `read`、`write`)抽象了读写行为,并用一个 `union` 联合体统一了对内存缓冲区和文件的处理,使得一套代码能同时服务于内存缓存和磁盘文件两种场景,设计上颇具巧思。 接着,作者以 `rdbSave()` 函数为主线,通过代码注释的方式,清晰地勾勒出整个 RDB 写文件的流程:从创建临时文件、初始化 `rio` 结构,到遍历每个数据库、写入操作码和数据项。这个过程不仅解释了数据是如何被序列化到磁盘的,也揭示了 BGSAVE 等后台操作的基础——主进程 `fork` 出子进程来执行这个主逻辑,从而避免阻塞服务。 对于想了解 Redis 如何将内存数据“快照”到硬盘的开发者而言,这篇文章提供了一个从数据结构到执行流程的清晰视角。

IT 累计浏览 2,048

实用命令行工具详解(二)—siege

这篇讲的是Linux下的负载测试工具siege如何模拟真实用户行为。文章开篇就点明了它与Apache ab的关键区别:siege能从URL列表随机请求,更适合仿真多用户并发负载,而ab则在追求极致性能基准时更精确。 文章详细展示了siege的多种实战用法。比如,你可以用 `siege -c 500 -r 50 -f url.txt` 模拟500个用户重复请求50次;也可以用 `-t10M` 参数让压测持续10分钟。它甚至能从服务器的access.log中提取URL,用来复现历史访问场景,这对于重现问题非常实用。 对于测试结果,文章逐一解读了输出指标,像“Transaction rate”即我们常说的QPS,“Response time”反映网络连接速度。最后部分还梳理了关键参数,如 `-c` 控制并发量、`-d` 设置请求间隔、`-l` 保存日志等,帮助读者根据自身环境灵活配置。 整体上,这篇文章没有停留在理论介绍,而是通过具体命令和输出示例,手把手地带读者用起来。对于需要快速评估Web应用压力承受能力的开发者来说,这是一份清晰的速查手册。

IT 累计浏览 3,440

贝尔实验室的历史

这篇讲的是那个诞生了Unix、C语言和晶体管的传奇实验室——贝尔实验室的完整身世。 作者从自己学习Go语言时产生的困惑出发:电话发明者贝尔和实验室到底是什么关系?实验室在AT&T、朗讯、阿朗等不同名字间辗转,其本质是什么?文章沿着电话发明者亚历山大·贝尔1876年创立贝尔电话公司这条线索,一路梳理了其后继者AT&T公司的发展,并重点追踪了隶属于AT&T的贝尔实验室如何成为“科技圣地”,最终在产业变革中被拆分重组的历史脉络。 它理清了从贝尔个人发明到庞大研发机构,再到被并购拆分的完整演变路径。对于想弄明白“贝尔实验室”这个闪耀又复杂的名字背后究竟是一段怎样的公司史与科技史的读者,这篇梳理提供了一个清晰的时间线与故事框架。

IT 累计浏览 3,083

第一代程序员王小波

这篇讲的是作家王小波一个鲜为人知的身份:中国第一代程序员。文章从作者偶然读到的信息切入,揭示了这位文学天才在上世纪90年代初,自学汇编、C语言等,独立开发出中文编辑器与输入法的经历。 文中呈现了大量细节。王小波为解决统计工作需要和对软件的好奇,钻研数据结构、算法乃至编译原理,甚至为了优化自己的286电脑而深入内存管理。他与友人的书信往来里,详细讨论了软件开发、B树结构、递归算法等技术话题,其专注与钻研程度不亚于专业工程师。 更有趣的是,他小说中诸多充满想象力的理工男形象和荒诞发明(如开根号机器),正源于这份极客精神。文章通过还原一个在代码世界里同样追求“特立独行”的王小波,让我们看到独立之精神如何贯通于他的文字与算法之中。

IT 累计浏览 5,716

为什么C语言需要函数声明

这篇讲的是作者从同事遇到的一个诡异bug出发,揭示了C语言中“函数声明”为何不可或缺。同事的代码中,一个返回double的函数,在函数内部打印的值和外部接收到的值差异巨大。通过反汇编,作者发现了关键线索:编译器生成了一条将整型转换为双精度浮点的指令(cvtsi2sd)。 根因在于,当函数在别的源文件中定义,而调用方没有其声明时,编译器在编译阶段并不知道该函数的真实面貌。它会默认函数返回整型(放入eax寄存器)。由于调用方实际期望一个浮点值(应放入xmm0寄存器),编译器就在调用后强行做了一次类型转换,从而导致了值的错误。问题不仅限于返回值,未声明的函数参数也会导致编译器忽略类型检查,可能引发更隐蔽的栈或寄存器传参错误。 作者指出,现代编译器如GCC能通过-Wimplicit-function-declaration选项对此发出警告。根本的解决之道是养成良好习惯,开启-Wall选项,并确保在使用任何外部函数前都进行正确声明。

IT 累计浏览 7,642

从C语言的Hello World说起

这篇讲的是,很多初学者虽然写过Hello World,但对背后的编译过程一头雾水。作者就从最简单的`printf("hello world\n");`出发,详细演示了如何在Linux下用GCC命令一步步将其变成可执行文件。 文章没有停留在“运行”层面,而是拆解了`gcc -g -Wall hello.c -o hello`这条命令里每个选项的具体含义:`-g`为调试留后路,`-Wall`让编译器“多嘴”以暴露问题,`-o`指定输出文件名。甚至讨论了从简陋的`main()`到规范的`int main()`并返回0的代码改进。 更硬核的部分在于,它图解并分步剖析了整个编译流水线:预处理如何把`#include`的头文件展开成一个巨大的.i文件;编译器又如何将C代码翻译成汇编语言;最后由汇编器和链接器生成最终的机器码。每一步都附有具体的GCC指令示例,比如用`gcc -E`单独查看预处理结果。 这文章相当于带读者重新走一遍当年可能只按了“运行”按钮就略过的路程,把“从源码到程序”的黑箱给拆开了看。对于想补上系统编程基础课的人来说,这种从Hello World切入的硬核拆解挺扎实。

IT 累计浏览 5,115

do{...}while(0)的意义和用法

作者从Linux内核和开源项目中频繁出现的 `do{...}while(0)` 代码片段切入,详细拆解了这个看似别扭的写法背后的设计考量。这种写法主要解决宏定义中复合语句在条件判断中可能引发的意外行为,比如用 `if` 直接包裹多条语句时,else 分支容易产生语法歧义。 文章通过几个简洁的宏定义示例,对比了不同写法在实际预处理后的差异,揭示了 `do{...}while(0)` 如何像一个“安全的空壳”,既保证了宏在语法上的完整性,又确保了宏展开后在任何上下文中都能按预期执行。核心巧妙之处在于,它利用了 `do...while` 循环结构只执行一次的特性,来安全地封装多条语句,同时不会引入额外的运行时开销。 这篇文章清晰展现了这一技巧如何兼顾代码的健壮性与可读性,对于理解底层代码风格和编写更安全的宏非常有帮助。

IT 累计浏览 3,203

弱类型?C语言参数提升带来的一个陷阱

这篇讲的是一个常见的C语言认知误区如何演变成实际的编码陷阱。作者从“C语言是弱类型语言,允许隐式转换”这个广泛流传但不够精确的说法出发,讲述了一段近期经历。核心问题在于,C语言的参数提升规则(如`char`、`short`在函数调用时自动提升为`int`)会在我们不察觉时改变变量的实际类型,从而引发隐蔽的逻辑错误或数据截断问题。文章深入剖析了C语言隐式类型转换的机制,特别是整型提升(Integer Promotion)的具体行为,并指出了它与“弱类型”概念的本质区别。作者通过自己的困惑,最终澄清了标准要求,并给出了编写更安全、可预测代码的实用建议。

IT 累计浏览 5,628

C语言的那些个关键字们

作者分享了一次在感冒状态下参加技术面试的真实经历。文章从作者带病前往心仪公司面试开始,描述了因迟到引发的紧张情绪,以及在高压时刻身体出现的意外反应——鼻涕突然停止了。这个细节生动展现了面试者对机会的重视,以及压力如何影响生理状态。作者以幽默的口吻,将个人体验与技术面试的常见挑战相结合,核心观点在于:在技术能力之外,心态管理和应变能力同样决定面试成败。对于读者,尤其是常面临面试的技术人员,这个故事提醒我们,突发状况下保持冷静的重要性,以及如何将压力转化为动力。文章通过这个小插曲,启发读者在技术学习之外,也需培养心理韧性,以更从容地应对职业中的不确定性。

IT 累计浏览 2,729

Linux 内核中的 KMP 实现

这篇讲的是Linux内核里一个你可能没想到的细节:它自己也实现了一套KMP算法。当我们谈到内核,常想到进程调度、内存管理,但字符串搜索同样是基础需求,无论是解析命令行参数还是处理网络协议。代码就藏在`lib/ts_kmp.c`里。 文章带我们看了这套实现的思路。它并非对教科书算法的简单照搬,而是充分考虑了内核环境的特殊性:比如如何与内核的内存管理机制配合,如何在内核态下追求高效与安全的平衡。作者拆解了其数据结构与函数逻辑,展示了从模式串预处理到文本匹配的完整流程,让我们看到一个经典算法是如何在贴近底层的场景中“落地生根”的。 读下来你会发现,即使是处理字符串搜索这样的“小事”,内核开发者也展现了其严谨和巧妙的设计,确保既可靠又高效。对于想了解内核实现细节的读者,这是一个很好的切入点。

IT 累计浏览 2,393

MooC的一些设计思路

这篇讲的是作者在设计 MooC(大规模开放在线课程)平台时的一些思考路径。作者从实际教学场景出发,直面传统在线课程单向灌输、完课率低的核心痛点,核心思路是将课程从“观看的视频”转变为“可交互的学习项目”。 具体设计上,文章拆解了几个关键模块:如何把知识体系切分成颗粒度适中、可独立完成的“任务单元”,每个单元都配备可验证的实践目标(比如一段可运行的代码或一份分析报告);如何利用轻量化的代码沙盒与即时反馈机制,让学习者能在“做中学”;以及后台如何通过学习行为数据,为助教提供干预依据。 最有趣的部分在于作者对“进度条”的重新定义——它不再只是视频的观看比例,而是综合了任务完成度、社区贡献与代码提交质量的动态学习画像。这种设计将评估点从“有没有看完”巧妙地转向了“能不能做到”,为提升在线学习的深度和留存率提供了一套扎实的实现方案。

IT 累计浏览 2,038

Linux服务器时间相关结构体和函数整理

Linux服务器开发中,时间处理是绕不开的基础,但不同场景下到底该用哪个时间类型?这篇讲的是作者从梳理Linux下常用的时间类型出发,整理了time_t、struct timeb、struct timeval、struct timespec以及clock_t、struct tm这几种核心结构体。 文章的核心价值在于对它们的特点和适用场景进行了清晰的对比。例如,time_t精度为秒,通常用于简单的日志时间戳;struct timeval和struct timespec则提供了微秒乃至纳秒级的精度,是进行高精度计时或sleep操作时的首选。作者还提到了struct timeb这类精度较低但在某些旧代码中仍会出现的类型。 对于需要使用clock_t进行CPU时间测量,或使用struct tm进行日期时间格式化与解析的场景,文章也指出了关键差异。这种梳理能帮助开发者在精度、平台兼容性、使用便利性等维度,为自己的项目做出合适的选择,避免因类型混淆导致的计算错误或性能问题。

IT 累计浏览 3,637

关于内存的申请与释放

这篇讲的是C/C++开发中内存管理的核心痛点。作者从实际项目中常见的内存泄漏和重复释放问题切入,对比了传统手动管理(如malloc/free)与现代C++智能指针(如shared_ptr、unique_ptr)两种范式。文章不仅解释了它们在实现机制上的关键差异——比如引用计数与作用域绑定如何工作,还通过代码实例展示了不当使用会导致的具体后果,比如循环引用造成的泄漏。最后,作者总结出清晰的选择指南:对性能敏感、生命周期明确的场景,手动管理或unique_ptr更高效;而对于对象所有权复杂、需要共享的场景,shared_ptr则是更安全的选择。

IT 累计浏览 3,661

PHP扩展开发:第一个扩展

这篇讲的是如何亲手创建你的第一个PHP扩展。在上一篇搭建好开发环境之后,作者直接从最基础的步骤开始,采用最简单直接的方式引导读者完成整个流程。 文章没有空谈理论,而是聚焦于动手实践。作者可能会演示创建一个“最小化扩展”的完整步骤,让读者理解扩展的基本骨架和必要文件。你会看到如何编写声明扩展信息的代码,以及如何通过标准的构建流程,将这段代码编译成PHP能够加载的.so动态库文件。整个过程旨在消除初学者的神秘感,证明创建一个能工作的PHP扩展并不复杂。 对于想要深入理解PHP底层,或希望为语言添加自己定制功能的开发者来说,这是一个非常扎实的起点。它跳过冗余的解释,用一条清晰的路径,让你的第一个扩展从零到运行起来。

IT 累计浏览 4,101

深入了解C语言

这篇讲的是在Dennis Ritchie先生逝世后,作者对C语言的一次深度回顾与致敬。文章指出,尽管C语言影响了C++、Java、JavaScript等无数现代语言,但很多程序员对其理解仍停留在表面。 作者提到,此前网站上的《C语言的谜题》和《谁说C语言很简单?》已经揭示了C语言的一些复杂性和精妙之处。而这篇新文章,旨在更进一步,从C语言的设计哲学和底层机制出发,带读者理解它为何能历经数十年而不衰。它不只是一门语法课程,更是关于如何真正掌握一门语言本质的思考。 文章最终将学习C语言的意义,提升到理解现代编程语言根基的高度。对于开发者而言,这既是对一位巨匠的缅怀,也是一次回归本源、审视自身技术根基的机会。