
C/C++
文章平均质量分 61
主要分享C/C++开发相关的知识
WongKyunban
这个作者很懒,什么都没留下…
展开
-
C语言的递归与尾递归
递归的优点为某些编程问题提供了很简单的解决方案,缺点是一些递归算法会快速消耗计算机的内存资源。有时递归算法不是很好阅读和维护。尾递归是最简单的递归形式,它的特点就是将递归调用放在函数的末尾,即正好在return语句之前。C语言允许函数调用自己,这种调用过程就叫递归。原创 2025-02-16 20:32:56 · 142 阅读 · 0 评论 -
C语言中的文件概念
另一种方式是存储文件的大小的信息,Unix使用这种方法处理所有的文件。操作系统的差异导致它有不同的底层I/O实现,这里的差异是多方面的,如系统存储文件的方式的不同,在有的系统上把文件的内容储存在一处,而文件的相关信息存储在另一处;在处理文件方面,不同的系统也可能表现出差异,如有的系统使用单个换行符标记行末尾,有的系统可能使用回车符和换行符的组合来表示行末尾。这样,不同的操作系统可以有不同的底层I/O实现,用户通过使用C标准的文件处理模型和标准I/O函数,就可以获得统一的使用界面。原创 2025-02-16 12:49:22 · 312 阅读 · 0 评论 -
C语言中的对象、左值、右值、序列点、副作用的概念
序列点是程序的执行点,在C语言中,语句中的分号标记一个序列点,在该点上,所有副作用都在进入下一步之前发生,即在一个语句中的赋值运算、递增运算、递减运算对运算对象的修改必须在程序执行下一条语句之前完成。sizeof以字节为单位返回对象的大小,它的返回类型是size_t这是一个无符号整型数,用size_t时,编译器会根据不同系统来替换具体的整型类型。因此,对象指的是实际的数据存储,而左值是用于标识或定位存储位置的标签。副作用也是一个C语言的术语,它是指对数据对象或文件的修改。num是可修改左值,5是右值。原创 2025-02-15 23:32:59 · 328 阅读 · 0 评论 -
C语言函数的实参与形参与缓冲区的概念
在C语言中,实际参数是传递给函数的特定值。形式参数是函数中用于储存值的变量。缓冲区刷新是指把缓冲区中的数据送到屏幕或文件的行为。原创 2025-02-15 23:15:53 · 108 阅读 · 0 评论 -
C语言中的常量与只读变量,#define与const的区别
代码在编译时就需要确定好数组的长度,所以只能用#define定义的宏常量,const的作用是限制变量为只读,它的值只有在运行时才能够确定,因此用const的变量来指定数组长度会报错。这条定义宏的语句,是不是很熟悉,这条预处理指令会在编译器编译前把源文件中使用到这个宏的地方都先展开。表明C处理器需要在编译器接手工作之前先处理这条指令。因为它们的值都不能够改变,都是它们的意义却是不同的。原创 2025-02-15 23:08:28 · 345 阅读 · 0 评论 -
C语言编译机制
o目标文件只包含编译源文件后的机器语言代码,不包含标准库函数的代码(库文件中有许多函数的目标代码),它不能直接运行,因为它缺失启动代码,启动代码充当程序与操作系统之间的接口。C的精神告诉你,它相信你(程序员)能够控制好,能够组织好,它不会在语言层面设置障碍去阻止你做任何事,它时刻保持语言的精练、简单,高效。编译器把源文件(扩展名为.c的文件)编译出中间代码(中间代码有很多种形式,如.s编译代码、.o目标代码),链接器再将其与其他代码连接在一起生成可执行文件。所以你负有责任去管理你的程序过程。原创 2025-02-15 17:37:22 · 212 阅读 · 0 评论 -
计算机中数据的表示
对于计算机中的二进制的解析完全取决于具体的机器指令,也就是说对于最高位是不是符号位,要不要取负权重等问题,要依赖于具体的机器指令,和二进数本身关系不大,如对于内存中的二进制数1111 1011,有的指令读取后,会将其视为有符号数,而有的指令读取后则会将其视为无符号数。+0, -0在系统中的表示法是一样的,而原码和反码都做不到。原码没有办法表示+0和-0,它只能表示+0,反码就更加不行了,最反后就是另一个值了。根据前求负数的补码的过程,我们可知结果的最高位总是1,这就是我们常说的符号位。原创 2025-02-08 10:20:44 · 977 阅读 · 0 评论 -
汇编指令和机器码的区别
(本例子是在apple m1架构平台上进行的,编译出来的汇编代码和机器码与在x86架构下编译出来的会有所不同。不同架构的平台的对应的汇编代码与机器码也是不相同的)(本例子是在apple m1架构平台上进行的,编译出来的汇编代码和机器码与在x86架构下编译出来的会有所不同。不同架构的平台的对应的汇编代码与机器码也是不相同的)如汇编的ret指令对应的机器指令在我运行的平台上就是d65f03c0.编译出对应的汇编源文件*.s。将可执行文件反编译出来。原创 2025-02-08 09:00:51 · 266 阅读 · 0 评论 -
X86中的常用寄存器
RSI, RDI, R8, R9还可以在调用函数时传递参数。原创 2025-02-07 23:20:53 · 203 阅读 · 0 评论 -
电路基本原理
当其中一个输入为高电平,另一个输入为低电平时,上面输出1,下面的输出就是0,结果就是二进制的01.当输入都为高电平,即1时,上面的输出就是0,下面的输出就是1,结果就是二进制的10.输入都是高电平,才会输出高电平,否则没有输出。只要其中一个输入是高电平,就会输出高电平。输入高电平,则输出低电平。输入低电平,则输出高电平。输出电平与输入电平相反。原创 2025-02-07 23:14:18 · 239 阅读 · 0 评论 -
CPU的基本结构
部件之间的通信是由各种各样的总线来完成。以内存为例,地址总线传输要访问的内存地址,数据总线传输读写的数据。在实际中,有的总线地址和数据是分离的,有的是同一根分时复用。北桥芯片也集成了内存控制器,用来控制与内存的通信。目前,最新的主板上,就没有北桥芯片了,因为北桥的功能已经被集成到CPU中去了。FSB总线:前端总线(Front Side Bus)是CPU和北桥传递的所有数据用的,FSB总线的频率直接影响到CPU访问内存的速度。PCI总线:这是一种高性能局部总线,CPU和外设之间的高速通道。原创 2025-02-07 22:58:19 · 324 阅读 · 0 评论 -
Vim跳转文件及文件行结束符EOL
在Windows上,行尾就不只使用 LF 这一个字符了,在 LF 前面会多一个 CR,编码值为 13(U+000D)。文本文件里存放的是用行结束符(EOL,即 End of Line)隔开的文本行,二进制文件里则没有这样的明确分隔符。使用 Vim 编辑的文本文件,最后一个字符通常是 LF(除非使用 Mac 行尾风格,则结尾是 CR)。在 Unix 或类Unix上,这个 EOL 在存盘时使用的字符是 LF,编码值是 10(U+000A)。可以在分割的窗口打开跳转的文件,不过在我的实验不是次次都成功。原创 2025-02-06 14:14:53 · 492 阅读 · 0 评论 -
Vim 多窗口编辑及文件对比
在光标所在的窗口,输入分割窗口命令就会对那个窗口进行分割。设置窗口高度,默认为纵向占满,利于专心编辑某个文件。只保留当前窗口,关闭其他所有窗口。只保留当前窗口,关闭其他所有窗口。默认使用水平分割的方式。把当前窗口横向一分为二。把当前窗口纵向一分为二。原创 2025-02-05 19:01:26 · 532 阅读 · 0 评论 -
C 标准库提供的进程控制
上面程序调用函数 atexit 为程序注册了一个回调函数,注册回调函数成功后,atexit函数会返回0。这个函数会在程序显式调用 exit 函数时,或从 main 函数内正常退出时被触发。在对应的回调函数 exitHandler 中,调用用 getenv 函数,获取并打印了当前宿主机上环境变量 PATH 的值。原创 2025-02-03 10:56:05 · 242 阅读 · 0 评论 -
C语言中的信号量
硬件中断直接由硬件触发,如磁盘完成了某次由用户程序指定的 IO 操作后,就会通过硬件中断的方式来通知 CPU 这一消息,并让 CPU 进行后续的处理。此时,如果应用程序并未设置自定义的信号处理程序,则操作系统将会执行默认信号处理程序中的逻辑,一般是直接终止当前程序的运行。在信号处理的过程中, CPU 从用户程序到信号处理程序的执行流程转移。当上述程序访问了非法内存,操作系统便会将信号 SIGSEGV 发送给当前进程,并之前通过 signal 函数注册的信号处理信息,调用用户自定义或默认的信号处理函数。原创 2025-02-03 09:54:30 · 353 阅读 · 0 评论 -
在C语言中使用条件变量实现线程同步
在多线程应用中,当某个线程的执行依赖于另一个线程对数据的处理时,这个线程可能没有被阻塞,只是不断地检查某个条件是否成立了(这个条件就是另一个线程对数据处理的结果的指示器),这是一种“忙等待”的方式实现线程间的同步。这样一来,某个线程可以在完成了某件事情后,通知并唤醒等待线程,让其继续工作,完成接下来的任务。在上述程序中,在 main 线程中,调用了与条件变量相关的函数 cnd_wait。在我们的例子中,只有 main 函数对应的一个线程,所以此时,互斥量将被重新上锁,main 线程将继续执行接下来的指令。原创 2025-02-02 22:13:02 · 386 阅读 · 0 评论 -
实现C语言的原子操作
我们一般都是在多线程环境中,才会需要原子操作的支持。因为当多个线程中对共享资源进行原子操作时,编译器和 CPU 将能够保证这些操作的正确执行。当该线程将整个原子操作全部执行完毕后,其他线程才可以继续执行同样的操作。与使用互斥量相比,原子操作可以更加清晰和方便地抽象并行代码,而不需要频繁进行加锁与释放锁的操作。从性能角度来看,原子操作的执行通常直接依赖于 CPU 提供的相应的原子机器指令。而使用互斥量则需要让线程阻塞,还要频繁进行上下文切换,比较之下,原子操作的性能一般会更好。原创 2025-02-02 20:50:52 · 438 阅读 · 0 评论 -
在C语言多线程环境中使用互斥量
互斥量就像是一把锁,在一个线程在访问某个共享资源前,需要对互斥量进行加锁操作,其他线程想要对互斥量加锁就会被阻塞,直到当前线程释放该锁。当锁被释放后,被阻塞的线程都开始继续执行,并再次重复前面的步骤,开始争夺可以对互斥量进行加锁的操作。如果有十个银行账号通过不同的十条线程同时向同一个账号转账时,如果没有很好的机制保证十个账号依次存入,那么这些转账可能出问题。我们可以通过互斥量来解决。互斥量这种方式,可以保证每次只有一个线程在操作共享资源。C标准库提供了这个互斥量,只需要引入threads.头文件。原创 2025-02-02 13:20:32 · 172 阅读 · 0 评论 -
C++如何遍历数组vector
在C++中,vector是一个可变数组。那么怎么遍历它呢?我们以for循环为例(while循环,大家自己脑补)。原创 2025-01-01 21:40:38 · 330 阅读 · 0 评论 -
在类Unix平台实现TCP服务端
我们没有指定hints.ai_family = AF_INET或 AF_INET6,因为getaddrinfo可以动态决定它的具体类型,也就是我们可以同时兼容IPv4 和IPv6.上一步只是用本地地址信息创建了socket,还要将这个socket与本地地址绑定起来,才能真正关联起来。由bind函数来完成。调用listen函数让socket可以监听外界对它的访问。我们这里设置了最多有10个等待处理的进来的访问,换句话说,原创 2024-04-07 00:42:41 · 477 阅读 · 0 评论 -
在类Unix平台实现TCP客户端
我们这个TCP客户端将从命令行接收两个参数,一个是IP地址或域名,另一个是端口,并尝试连接在这个IP地址的TCP服务端。原创 2024-03-17 18:55:39 · 1115 阅读 · 0 评论 -
C++ lock_guard的使用
它的构造函数接受一个互斥量my_mutex初始化了一个对象,因为是在test()函数中调用的,那么构造出来的对象会被放到栈内存空间。在构造时,它顺便调用了mutex的lock函数,对函数体进行了加锁,当test()函数执行完时,栈里的东西都会被销毁,包括创建出来的lock_guard对象,此时lock_guard对象的析构函数就会被调用,在它的析构函数里,就可以调用mutex的unlock函数进行解锁。注意:用new运算符产生的对象,是没有这一特点的,因为new出来的对象,需要你主动去delete。原创 2024-02-18 20:23:21 · 438 阅读 · 0 评论 -
C++单例模式的实现
单例模式就是在整个程序运行期都只有一个实例。在代码实现方面,我们要限制new出多于一个对象这种情况的发生。而不是仅仅依靠无保障的约定。目前大多数的编程语言的做法都是私有化构造函数,对外提供一个获取实例的接口。这样做的目的使实例的创建不能在类外部完成,这样我们只需要在内部保障实例只创建一次即可。定义单例基本上来说是很简单的,就是先私有化构造函数,单例内部new出这个实例,并对外提供获取实例的接口。在这里我想特别分享一下,为什么要弄一个内部类的作用。目的只有一个就是当程序退出时主动delete掉实例。原创 2024-02-17 19:04:20 · 545 阅读 · 0 评论 -
C++中的互斥量
互斥量就如同一把锁,在同一时间,多个线程都可以调用lock成员函数尝试给这把锁头加锁,但是只有一个线程可以成功给这把锁加锁,其他没有加锁成功的线程的执行流程就会卡在lock语句行这里不断地尝试去加锁,一直到加锁成功,执行流程才会继续走下去。sum变量是我们想要保护的对象,因为多个线程对sum进行加1时,如果在同一时刻,多个线程同时修改sum变量,那么最终得到的累加结果就有可能是错的。上面的例子中使用一把锁还是比较简单,当多把锁一起使用时,就可能会因为思考不周导致死锁出现。原创 2024-02-17 14:43:07 · 221 阅读 · 0 评论 -
C++ lamda表达式和重载圆括号来创建子线程
【代码】C++ lamda表达式和重载圆括号来创建子线程。原创 2024-02-16 15:23:30 · 250 阅读 · 0 评论 -
C++多线程编程
在编程的实践中,一般来说,主线程必须等待子线程结束才结束,所以上面的程序,如果不调用join等待子线程执行完毕,主线程就会先结束,主线程先结束了,还没有执行完的子线程就会被操作系统强制终止。一个程序的子线程,并不是越多越好,因为每个线程都需要有一个独立的堆栈空间(这个耗费内存),线程间的切换需要保存许多中间状态等(即上下文切换,若线程太多,上下文切换就会很频繁,上下文切换是必须的,但是这种切换如果是没有意义的额外工作,那么只会浪费本属于程序运行的时间)主线程执行到下面这行就阻塞在那,直到子线程执行完毕。原创 2024-02-15 23:49:29 · 747 阅读 · 0 评论 -
用C语言列出Linux或Unix上的网络适配器
sys/socket.h 定义主要socket的操作和结构体,如sockaddr_in、AF_INET(IPv4地址族)、AF_INET6(IPv6地址族)等。netdb.h 这里包含许多对网络操作的定义 ,如addrinfo结构体,这里面有AI_NUMERICHOST,这是说返回数字主机地址作为名字等等。ifaddrs.h 定义ifaddrs结构体和函数 getifaddrs, freeifaddrs。stdio.h 提供了通用文件操作的支持和窄字符输入输出的能力,如printf等。原创 2024-02-10 14:05:04 · 1816 阅读 · 0 评论 -
在Linux中用C语言实现Socket通信
stdio.h : 这个文件头文件是标准的输入输出,StandardInputOutput。这个头文件主要涉及文件相关的输入输出操作。典型的方法printf() , scanf(),getc(), putc()。怎么理解这里文件呢?在Linux,有一个基本的原则,键盘、显示等这些操作都会作为文件来对待。事实上,键盘输入是默认的stdin文件流,显示输出是默认的stdout文件流。StandardL。原创 2024-01-28 17:48:12 · 2089 阅读 · 0 评论 -
C++ Lambda表达式
return c;y(100);原创 2023-02-26 13:59:21 · 752 阅读 · 1 评论 -
带你去了解什么是makefile文件
GNU make命令是用来控制从源文件生成可执行文件或非可执行文件的方式。那么make命令又是通过makefile文件来控制了。所以了解makefile文件就显得很有必要了。目标:它一般是一个由程序产生的文件的名字,比如说目标文件的名字或可执行文件的名字。它也可以是一些动作的名字,比如“clean”先决条件是用来了创建目标文件的文件,一个目标文件通过依赖几个文件。命令是make执行的动作,可能包含多个命令。它们写在同一行或者各自一行。在每个命令前,我们要按一下tab键。原创 2023-01-24 12:34:22 · 1734 阅读 · 0 评论 -
带你了解GNU Make
GNU Make是一个控制编译过程的工具。它控制程序的源文件如何生成可执行文件或非源文件,其实就是指定一种方式自动化我们的构建过程。我们先来了解一下,一个程序是怎么被编译出来的。在得到一个可执行文件之前,要先编译出目标文件,再把目标文件链接起来。(注意:编译过程中,会先做预处理,把一些宏展开,include等包含进来等,得到*.i或*.ii,接着编译得到汇编程序*.s,再汇编得到目标文件*.o,最后把目标文件链接起来得到可执行文件)。原创 2023-01-23 17:39:47 · 1858 阅读 · 0 评论 -
GDB的常用命令
GDB是一个调试程序,可以用来调试C/C++程序。这个C/C++要产生符号表才能使用GDB调用。GDB常用命令。原创 2023-01-23 02:30:59 · 2102 阅读 · 0 评论 -
g++的命令选集
这一次,主要想分享一下个人认为比较有意思的g++命令。也就是说不会涵盖所有的命令。-显示所有可能的警告信息。原创 2023-01-22 01:58:15 · 2590 阅读 · 0 评论 -
如何在Linux上搭建C++开发环境
工欲善其事,必先利其器!我们要在Linux上开发C++程序,就要先搭建好它的开发环境。原创 2023-01-16 01:12:57 · 9954 阅读 · 2 评论 -
C++模板
使用模板时,我们只需要将具体的数据类型作为参数传给模板,这样编译器在编译时会像宏替换一样将模板上的占位符替换成指定的数据类型,与宏展开不同的是,在模板展开前,编译器会先做类型检查。举个例子来说明模板:比如说很多数据类型都需要max()求最大值的方法,那么我们可以写一个max()的方法,然后接受一个数据类型的参数,从而为不同数据类型提供求最大值的方法,而不是为不同的数据类型都实现同样的方法。即使模板的源码只包含方法或类,但是编译后的代码可能会包括多份同样方法或类的的代码。的一些实例,现在我们来看一下。...原创 2022-08-31 00:17:52 · 1208 阅读 · 0 评论 -
C++ Lambda表达式
什么是Lambda表达式呢?λ演算(λ-calculus)是一个形式化的数学逻辑系统,它基于函数的抽象和应用,使用变量绑定和替换来表示计算。从C++11开始可以使用Lambda表达式创建匿名函数对象(闭包),它可以作为一个参数传递给另一个函数。原创 2022-08-22 01:15:51 · 1124 阅读 · 0 评论 -
C++虚基类、虚函数、虚析构函数、纯虚函数
举个例子来说明一下什么是虚基类吧。return 0;}BaseDerived ABaseDerived B从上面打印出来的结果可以看出Base在内存中有两个副本。但实际上只需要一个Base副本就可以了。BaseDerived ADerived B此时Base在内存只有一份了。...原创 2022-08-16 00:27:09 · 2196 阅读 · 1 评论 -
C++指针的小知识
指针为什么在使用时,需要强制类型转换。原创 2022-08-14 15:18:22 · 697 阅读 · 0 评论 -
C++构造函数
C++构造函数分两种:普通构造函数和复制构造函数。其中复制构造函数的参数为自身类型的常引用,即const 类名 &修饰。为什么要传个常引用呢?因为是引用,所以对引用的操作会影响到原来的对象。为了防止复制构造函数里对引用的修改,所以加上const去修饰,const修饰的对象是不能被修改的,包括它的任何成员。...原创 2022-08-14 13:54:01 · 2769 阅读 · 0 评论 -
C++全局变量与局部变量初始化的问题及存储类修饰符
一般来说,C++ 有三个地方可以声明变量:在函数或一个代码块内部声明的变量,称为局部变量。在函数参数的定义中声明的变量,称为形式参数。在所有函数外部声明的变量,称为全局变量。从上面的定义来看C++全局变量与局部变量就很好区分了。局部变量只能被函数内部或者代码块内部的语句使用,而全局变量的值在程序的整个生命周期内都是有效的。全局变量可以被任何函数访问,在整个程序中都是可用的。在程序中,局部变量和全局变量的名称可以相同,但是在函数内,局部变量的值会覆盖全局变量的值。1.局部变量和全局变量的初始化原创 2020-12-27 23:51:59 · 2101 阅读 · 0 评论