- 博客(286)
- 资源 (1)
- 收藏
- 关注
原创 dynamic_cast, static_cast以及reinterpret_cast介绍
/ C风格转换,无任何检查。// 在 PowerPC(大端)上:bytes[0] = 0x12, bytes[1] = 0x34, …// 编译时检查,安全。// 在 x86(小端)上:bytes[0] = 0x78, bytes[1] = 0x56, …// g++ -std=c++11 -frtti program.cpp // 启用(默认)// g++ -std=c++11 -fno-rtti program.cpp // 禁用。
2025-12-16 16:11:00
747
转载 30 天自制 C++ 服务器--Day5
试想,如果一个服务器同时提供不同的服务,如HTTP、FTP等,那么就算文件描述符上发生的事件都是可读事件,不同的连接类型也将决定不同的处理逻辑,仅仅通过一个文件描述符来区分显然会很麻烦,我们更加希望拿到关于这个文件描述符更多的信息。而通过指针,理论上我们可以指向任何一个地址块的内容,可以是一个类的对象,这样就可以将一个文件描述符封装成一个Channel类,一个Channel类自始至终只负责一个文件描述符,对不同的服务、不同的事件类型,都可以在类中进行不同的处理,而不是仅仅拿到一个int类型的文件描述符。
2025-12-11 16:00:51
16
原创 C++ 多态介绍
什么是多态?多态 = 同一接口,不同实现编译时多态(静态多态):函数重载、模板运行时多态(动态多态):虚函数public:// 纯虚函数public:public:i < 2;i++) {// 同一接口,不同行为// Circle::draw() 或 Square::draw()// 多态:通过基类指针调用派生类函数return 0;纯虚函数是 C++ 实现接口和抽象类的关键机制。它的主要用途是定义接口规范,强制派生类实现特定的功能。创建抽象类(不能实例化)
2025-12-10 14:52:28
404
原创 extern C介绍
基本概念extern “C” 是 C++ 中的一个链接规范(linkage specification),用于指定函数或变量使用 C 语言的链接规则。主要作用解决名称修饰(Name Mangling)问题cpp// C++ 编译器会对函数名进行名称修饰// 可能被修饰为 _foo_i// 可能被修饰为 _foo_d// 可能被修饰为 _foo_i_i// 使用 extern “C” 禁止名称修饰// 保持为 bar3. 基本语法单个函数声明cpp。
2025-11-20 16:25:52
679
转载 堆和栈的区别
当主函数要调用一个函数的时候,要对当前断点进行保存,需要使用栈来实现,首先入栈的是主函数下一条语句的地址,然后是调用函数的参数,一般情况下是按照从右向左的顺序入栈,之后是调用函数的局部变量,注意静态变量是存放在全局内存区,是不入栈的;栈,是一种向低地址扩展的数据结构,并且是连续的存储空间,所以栈顶和栈的最大容量是固定的,在windows下,栈的最大容量是2m或者是1m,是在编译的时候就已经确定的,当申请空间大于栈的剩余空间的时候,就会报错说明overflow,所以栈能够申请的空间是比较有限的。
2025-11-20 15:56:17
28
原创 虚析构函数的重要性
/ ❌ 只调用Base的析构函数,Derived的析构函数不会被调用!void acquire() override { /* 数据库特定的获取逻辑 */ }void draw() const override { /* 绘制圆形 */ }void draw() const override { /* 绘制矩形 */ }~Derived() override { // ✅ 正确调用派生类析构函数。void operation() override { /* 实现 */ }// 动态分配的资源。
2025-11-20 10:49:38
799
原创 a++、++a区别
2.在自定义数据类型时(主要指有类的情况),由于++a可以返回对象的引用,而a++一定要是返回对象的值(因为局部对象不能返回引用)。a=a+1: 虽然有点雷同于a+=1,但不同的是此时右值的a和1做相加操作,形成一个副本然后赋值给a,所以有额外操作。1.在内建数据类型时(即自增表示式的结果没有被使用,只是简单的用于递增操作),这时这两个表达式的效率是相同的。鉴于a++和++a的差别,C++Primer建议用++a作为for循环的递增量。a++:a先创建自身的一个副本,然后a自增1,最后返回副本的值。
2025-11-20 10:48:21
234
原创 UNUSED_ARG介绍
/ 必须传递user_data参数。UNUSED_ARG 是一个宏,用于显式标记函数中未使用的参数,主要目的是消除编译器警告并提高代码可读性。这是一个简单的宏,但在大型项目和跨平台开发中非常有用,能够保持代码的整洁和编译的清洁。// 使用 UNUSED_ARG - 无警告。消除编译器警告:关于未使用参数的警告。提高代码可读性:明确表达设计意图。保持接口兼容性:符合函数签名要求。支持未来扩展:保留参数供后续使用。示例3:算法库中的占位参数。2. 函数指针兼容性。示例1:信号处理函数。
2025-10-27 14:57:08
154
原创 关于stub和mock
第一部分:C/C++中的Mock和Stub区别基础概念在C/C++单元测试中:Stub(打桩):提供预设的返回值Mock(模拟):验证函数调用行为。
2025-10-27 10:13:30
162
原创 对象注册机制
这种模式在框架开发、插件系统、对象池、服务定位器等场景中非常常见,是一种强大的对象管理技术。aMap:通常是一个全局或静态的映射容器(如 std::map, std::unordered_map)aMap[n] = this 在构造函数中通常表示一种对象注册机制。自动注册:对象在创建时自动将自己注册到全局管理系统中。集中管理:所有同类对象可以在一个地方统一管理。查找机制:提供通过键值快速查找对象的能力。this:指向当前正在构造的对象的指针。整体意思:将当前对象注册到全局映射表中。场景2:消息处理器注册。
2025-10-21 14:22:09
156
原创 shell中的[]和[[]]比较
在Shell中,[ 和 [[ 都是用于条件测试的,但它们之间有一些重要的区别。[ 是传统Bourne shell的测试命令,而 [[ 是Bash等现代shell引入的增强版测试命令。下面详细说明它们的区别:语法和功能:[ 是一个内置命令,同时也是一个外部命令(通常是/bin/[),它要求参数和操作符之间必须有空格,并且最后一个参数必须是 ]。[[ 是一个Shell关键字,它提供了更强大的功能,比如模式匹配和正则表达式匹配,并且不需要对变量进行引号保护(因为不会进行单词分割和路径扩展)。字符串比较:在 [ 中
2025-10-21 13:57:01
312
原创 30 天自制 C++ 服务器--Day4
另一点是我们的程序会变得越来越长、越来越庞大,虽然现在才不到100行代码,但把所有逻辑放在一个程序里显然是一种错误的做法,我们需要对程序进行模块化,每一个模块专门处理一个任务,这样可以增加程序的可读性,也可以写出更大庞大、功能更加复杂的程序。仅仅六行代码就可以实现和之前一样的功能,这样的使用方式忽略了底层的语言细节,不用在程序中考虑错误处理,更简单、更加专注于程序的自然逻辑,大家毫无疑问也肯定希望以这样简单的方式使用socket。C++是一门面向对象的语言,最低级的模块化的方式就是构建一个类。
2025-09-18 10:42:26
434
原创 C++中的template介绍
模板是C++中最强大和复杂的特性之一,它支持泛型编程(Generic Programming),允许编写与类型无关的代码。模板使得我们可以创建通用的函数和类,这些函数和类可以处理多种数据类型,而无需为每种类型重写代码。
2025-09-02 16:45:05
355
1
原创 C++中的assign函数
assign函数是C++标准库中许多容器类(如vector、list、string等)提供的成员函数,用于替换容器中的内容。它提供了一种灵活的方式来修改容器内容,比直接赋值更灵活。
2025-09-02 13:58:29
677
原创 30 天自制 C++ 服务器--Day3
的核心原理在于改变事件通知模型:它通过在内核使用红黑树高效管理注册的文件描述符,利用回调函数在事件发生时直接将就绪项放入链表,并通过 epoll_wait 仅返回实际就绪的事件列表,辅以 mmap 减少数据拷贝。IO复用的基本思想是事件驱动,服务器同时保持多个客户端IO连接,当这个IO上有可读或可写事件发生时,表示这个IO对应的客户端在请求服务器的某项服务,此时服务器响应该服务。epoll监听事件的描述符会放在一颗红黑树上,我们将要监听的IO口放入epoll红黑树中,就可以监听该IO上的事件。
2025-07-16 15:02:04
1394
原创 effective c++---别让异常逃离析构函数
在C++中,从析构函数抛出未捕获的异常会导致程序崩溃(直接调用std::terminate)。// ❌ 致命错误!std::fstream:析构调用close(),但关闭错误仅设置failbit,不抛出。file.close()) { // 假设close()可能抛出异常。void close() { // 用户主动调用,可处理异常。// 必须确保close()不抛出。// 若析构函数抛出异常,程序直接终止,无法到达这里。提供close()/release()等方法。// 可安全抛出(但通常仍不建议)
2025-07-14 16:50:01
332
原创 30 天自制 C++ 服务器--Day2
然而对于socket,bind,listen,accept,connect等函数,我们都设想程序完美地、没有任何异常地运行,而这显然是不可能的,不管写代码水平多高,就算你是林纳斯,也会在程序里写出bug。,这个函数会打印出errno的实际意义,还会打印出我们传入的字符串,也就是第函数第二个参数,让我们很方便定位到程序出现错误的地方。到现在最简单的错误处理函数已经封装好了,但这仅仅用于本教程的开发,在真实的服务器开发中,错误绝不是一个如此简单的话题。通常来讲,当一个系统调用返回-1,说明有error发生。
2025-07-14 16:34:28
176
原创 Effective C++之定义式和声明式
定义式的作用是为编译器提供声明式(declaration)所缺失的详细信息,使得编译器能够正确生成代码或分配内存。定义式(Definition):提供声明所缺失的细节,使得编译器可以实际使用该名称(分配内存、生成代码等)。std::size_t numDigits(int number) { // 定义式:提供函数体。声明式仅告诉编译器“这是什么”,而定义式告诉编译器“这是什么以及如何实现/分配”。// 定义式:编译器为 x 分配内存。class Widget { // 定义式:列出类的成员。
2025-07-14 10:46:55
326
原创 30 天自制 C++ 服务器--Day1
socket 的原意是“插座”,在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。我们把插头插到插座上就能从电网获得电力供应,同样,为了与远程计算机进行数据传输,需要连接到因特网,而 socket 就是用来连接到因特网的工具。socket是什么?
2025-07-11 15:42:04
716
原创 timewait和msl介绍
修改内核参数(如 net.ipv4.tcp_tw_reuse、net.ipv4.tcp_tw_recycle,但后者在 Linux 4.12 后已移除)。此时连接并未立即关闭,而是会等待一段时间(通常是 2×MSL)后才彻底释放资源(如端口、内存等)。MSL 是报文的最大生存时间,TIME_WAIT 的持续时间(2×MSL)由它决定。避免旧连接的延迟报文干扰新连接:防止网络中延迟的旧数据包被误认为是新连接的数据。是 TIME_WAIT 计算的基础(TIME_WAIT = 2×MSL)。
2025-07-09 14:45:58
423
原创 poll的介绍
poll 是 Linux/Unix 系统中用于 多路复用 I/O 操作 的系统调用,允许程序同时监听多个文件描述符(File Descriptor, FD)的状态变化(如可读、可写、错误等)。水平触发(LT):就绪事件需及时处理,否则会重复通知(对比 epoll 的 ET 模式)。-1 出错(如被信号中断),可通过 errno 获取错误码(如 EINTR)。事件驱动:当任一被监听的 FD 就绪(如数据可读、可写)时,立即返回。效率 高(无需每次重置 FD 集合) 低(需每次重建 fd_set)
2025-07-07 17:05:09
1007
原创 #if 0介绍
在C/C++中,#if 0 是一种条件编译指令,其作用是临时或永久禁用一段代码,使其不会被编译器处理(相当于“注释掉”代码)。多行注释 /* */ 不能嵌套,而 #if 0 可以嵌套禁用包含注释的代码。#if 0 是代码的“开关”:比注释更灵活,适合临时禁用大段代码或条件编译。必须配对:#if 0 必须有对应的 #endif,否则编译报错。printf(“这段代码不会编译”);若需恢复代码,只需将 #if 0 改为 #if 1。#if 0 可以保留代码语法高亮,方便后续恢复。#if 0 直接禁用代码。
2025-07-07 10:27:01
511
原创 VRRP(Virtual Router Redundancy Protocol)详解
VRRP(虚拟路由器冗余协议)是一种网络容错协议,用于在多台路由器之间实现网关冗余,确保当主路由器故障时,备份路由器能无缝接管流量,从而保障网络的高可用性。它通过虚拟IP(VIP)和虚拟MAC地址实现透明切换,对终端设备无感知。厂商文档:华为《VRRP配置指南》、思科《HSRP vs VRRP》
2025-07-04 15:14:05
176
原创 粘包问题介绍
粘包问题是 基于流的传输协议(如TCP) 中的一种常见现象,指的是发送方连续发送的多个数据包,在接收方缓冲区中被合并成一个“大包”,导致接收方无法正确解析原始数据包的边界。缓冲区机制:为提高效率,TCP 可能合并多次发送的小数据包(Nagle算法)。接收方:可能一次性读取到 包A+包B(粘包),或分多次读取(半包)。发送方:快速连续发送多个小包(如 包A + 包B)。用特殊字符标记包结束(如 \r\n、0x00)。解决方案:长度字段(推荐)、分隔符、固定长度。在包头添加长度字段,明确告知接收方包体大小。
2025-07-03 17:40:31
714
原创 wireshark介绍和使用
Follow TCP Stream(右键数据包 → Follow → TCP Stream):查看完整会话(如 HTTP 请求/响应)。点击数据包:查看协议层级(如 Ethernet → IP → TCP → HTTP)。Statistics → Conversations:查看通信对端(IP/端口)。示例脚本目录:/usr/share/wireshark/plugins/官网:https://www.wireshark.org/基础流程:选择网卡 → 抓包 → 过滤 → 分析。
2025-07-03 17:29:56
776
原创 DPDK介绍与使用
首先确保您已经按照前面的指南安装并配置好了 DPDK 环境。学习 rte_ring、rte_mbuf 等核心数据结构。3.2 filter.c - 过滤器实现。3.3 main.c - 主程序。3.2 下载并编译 DPDK。3.4 绑定网卡到 DPDK。3. DPDK 安装与配置。根据自定义规则过滤数据包。3.3 配置大页内存。
2025-07-03 17:23:02
539
原创 mailbox 核间通信
Mailbox(邮箱) 是一种常见的核间通信(Inter-Processor Communication, IPC)机制,主要用于多核处理器(如ARM多核SoC、FPGA+CPU异构系统)或主从处理器(如MCU与DSP、CPU与GPU)之间的数据交换。Mailbox 是一种高效、低延迟的核间通信方式,适用于多核/异构系统的实时数据交换。在嵌入式Linux、RTOS及SoC设计中广泛应用,需结合硬件特性和软件框架灵活使用。
2025-07-01 16:48:28
1535
原创 缓冲区(Buffer)介绍与实现
环形缓冲区是高效的数据缓存方案,尤其适合高并发实时系统。核心实现:循环数组 + head/tail 指针 + 状态标记(full)。扩展优化:无锁设计、动态扩容、批量操作。经典应用:生产者-消费者模型、音视频流、网络通信。
2025-06-30 16:57:39
631
原创 static线程安全
public:// 声明classVar++;// 必须在类外定义静态成员t1.join();t2.join();// 应为 2return 0;规则:静态类成员需在类外单独定义(链接器需要实际存储)。修改时同样需要加锁。
2025-06-30 16:43:53
633
原创 生产者-消费者模型 和 操作系统信号定时调度
线程安全队列 使用互斥锁(pthread_mutex_t)和条件变量(pthread_cond_t)保护。使用 pthread_mutex_t 和 pthread_cond_t 实现同步。生产者定时器(SIG_PRODUCER)每 1 秒 触发一次。消费者定时器(SIG_CONSUMER)每 2 秒 触发一次。信号处理函数仅设置标志位,线程检测到标志位后执行任务。消费者线程 由另一个定时器信号触发,从队列读取数据。生产者线程 由定时器信号触发,向队列写入数据。
2025-06-27 10:49:44
235
原创 缺页中断(Page Fault)详解
缺页中断是操作系统中内存管理的关键机制,当进程访问的虚拟内存页面不在物理内存(RAM)中时,由 MMU(内存管理单元) 触发 CPU 异常,操作系统通过中断处理程序将缺失的页面从磁盘(如交换空间或文件系统)加载到内存,使进程继续执行。访问非法地址(如空指针),触发 段错误(Segmentation Fault),终止进程。页面在磁盘(交换空间或文件),需从磁盘加载到内存(I/O 操作,速度慢)。首次访问分配的内存时触发软/硬缺页(实际分配物理页面)。重新执行引发缺页的指令,此时页面已在内存,正常访问。
2025-05-30 10:10:49
980
原创 pmap中的mode列,脏页,写时复制
写时复制(Copy-on-Write,简称 COW) 是一种计算机编程中的优化技术,主要用于内存或存储资源的管理。其核心思想是:只有在真正需要修改数据时,才会执行实际的复制操作,从而避免不必要的资源开销。当某个进程尝试修改数据时,系统才会透明地为该进程创建一份独立的副本,后续修改仅影响副本,其他进程仍访问原始数据。多个进程/线程访问同一份数据时,最初共享同一份物理资源(如内存页、文件块),而不是立即创建副本。USS 可以通过pmap的所有值减去共享的包括-s的内存部分,得到吗?
2025-05-20 17:57:23
288
原创 vim的操作
宏: 是一组命令的录制,可以快速重放,适用于重复性操作。寄存器: 是存储文本、命令和宏的临时存储区,允许用户灵活地管理和使用这些数据。通过理解宏和寄存器的概念,您可以更高效地使用 Vim 进行文本编辑和操作。在 Vim 中,是一系列组合命令,涉及到插入模式和普通模式的操作。这段命令的作用是从当前光标位置向右移动 24 个字符,然后向下移动 4 行,删除该位置到当前行末尾的文本,最后在当前行末尾粘贴之前删除的文本。这可以用于快速编辑文本,特别是在处理块选择和文本替换时。cd ~ls -a。
2025-04-02 14:42:38
1298
原创 gdb使用
watchpoint是gdb中一个非常有用的功能,可以帮助开发者监视变量的变化,便于调试和分析程序的行为。通过设置 watchpoint,您可以更轻松地找到导致变量变化的代码位置。
2025-04-01 16:34:57
807
原创 多线程介绍
堆的共享特性要求在访问时注意线程安全,而栈的独立性使得线程之间的局部变量不会相互干扰。例如,线程 A 使用 malloc 分配内存,线程 B 也可以使用 malloc 分配内存,但需要确保对共享数据的访问是安全的。这意味着在同一个进程中的不同线程可以动态分配和释放堆内存。由于堆是共享的,多个线程可以同时访问和修改堆中的数据,这可能导致数据竞争和不一致性的问题。线程 A 和线程 B 各自的栈中可以有相同名称的局部变量,但它们是独立的。由于每个线程有独立的栈,因此线程之间的局部变量是相互隔离的,不会相互影响。
2025-03-25 14:51:15
510
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅