
C/C++
文章平均质量分 71
C/C++
百里杨
码农想飞~~
展开
-
负数在二进制中的表示方法
在二进制补码表示法中,负数是通过取其绝对值的二进制表示(即正数的二进制表示),然后取反(0变1,1变0),最后加1来得到的。在这种表示法中,符号位是最高位(Most Significant Bit, MSB)。原创 2024-06-20 17:58:46 · 2164 阅读 · 0 评论 -
获取树形结构中,父节点下所有子/孙节点(递归方式)
利用了递归方式,对形参parent节点下的所有节点进行遍历,并将该parent节点下所有子/孙节点,全部添加到一个List中,并返回给调用者。最后,分别打印输出China、SiChuan、GuangDong节点下的所有子/孙节点名称。这个类的函数比较简单,就是利用TreeItem类型,彼此依次添加,就可以形成树形结构。原创 2022-12-28 21:05:35 · 2970 阅读 · 2 评论 -
利用线程与环形缓冲区实现对数据的异步存储
利用线程与环形缓冲区实现对数据的异步存储一、流程图二、FileSave文件异步存储类三、测试代码一、流程图数据流首先,进入缓存至环形缓冲区,当缓冲区中一个缓存块被填满后,释放信号量给线程;线程被唤醒,从缓冲区中取出一个缓存块的数据,并写入文件。以上,就是2个主要过程,如此循环往复。当然还有很多细节没有介绍,诸如,缓存块读、写指针的控制等。二、FileSave文件异步存储类以上所讲过程,全部封装到了FileSave类中。数据推送接口,RealUCharPort.h#ifndef REAL原创 2021-01-27 18:26:51 · 657 阅读 · 0 评论 -
assert与if的区别
assert与if的区别1、检查函数实参有效性2、检查函数返回值有效性3、检查变量值有效性assert与if的区别:assert俗称断言,一般只在debug模式生效;release模式下,该语句不参与编译。if语句,无论debug还是release模式下,该语句均参与编译。这2个都是用来检查参数,是否符合一定条件的。这里介绍一种,使用时的区别办法:程序员主观上认为这是不可能的事,这种情况使用assert;而程序员很清楚的知道,这个是有可能发生的事,这种情况使用if。可能涉及到,用于检原创 2020-12-27 12:32:04 · 2023 阅读 · 1 评论 -
在Windows/Linux下使用popen函数执行命令
在win或linux下编写程序,在程序代码中想要通过执行命令的方式,获取一些信息,可以使用popen函数来实现。一、在Win下的_popen()函数在win下该函数,定义如下:FILE *_popen( const char *command, const char *mode );功能: 创建管道并执行命令,管道的另一端与标准输入或标准输出相关联,并返回与管道相关联的流。参数: command,需要执行的命令;mode,有如下4种选项:“r”,可以对返回的流进行读取“w”,可以对返原创 2020-12-05 17:24:51 · 6470 阅读 · 0 评论 -
在Windows/Linux下调用API函数实现重启系统
一、Linux下重启系统linux下很简单,直接看代码:#include <unistd.h>#include <sys/reboot.h>bool rebootSystem(){ sync(); if (reboot(RB_AUTOBOOT) < 0) { return false; } return true;}sync函数:将缓存中的数据写入磁盘,防止数据丢失。reboot函数:对于关机或重启,该原创 2020-12-04 15:31:29 · 1761 阅读 · 1 评论 -
显式链接、隐式链接和显式加载、隐式加载以及动态库路径查找
我们知道库一般有静态库和动态库2种:静态库是编译时就链接到可执行文件中的;动态库是在程序运行时再进行加载的。故本文讨论的链接与加载方式是指对动态库而言的。一、动态库的加载方式1、隐式加载 就是我们需要准备好.h、.lib或者.so,对头文件进行包含,并添加对lib的链接命令,来完成对库函数的调用。这种链接方式,称之为隐式链接。 在程序从开始运行时,就会按照系统中一定的搜索路径,寻找动态库,找到就自动加载它,才能成功运行程序,这些步骤,是系统自动完成的。 一般来说,隐式链原创 2020-11-24 21:29:50 · 3742 阅读 · 0 评论 -
如何判断当前程序是否正以管理员或root权限运行
在windows下,一般超级用户是管理员权限administrator;在linux下,一般超级用户是root。windows下,使用IsUserAnAdmin()函数进行判断;linux下,使用geteuid()函数进行判断。编写一个UAC.h文件,使得在win/linux均可以进行判断,如下:#ifndef UAC_H#define UAC_H#ifdef WIN32// for IsUserAnAdmin()#include <ShlObj_core.h>#prag原创 2020-11-23 12:00:00 · 3018 阅读 · 0 评论 -
std::vector使用要点总结
一、std::vector的6种初始化方式1、vector ilist1;默认初始化,vector为空, size为0,表明容器中没有元素,而且 capacity 也返回 0,意味着还没有分配内存空间。这种初始化方式适用于元素个数未知,需要在程序中动态添加的情况。2、vector ilist2(ilist);vector ilist2 = ilist;两种方式等价 ,ilist2 初始化为ilist 的拷贝,ilist必须与ilist2 类型相同,也就是同为int的vector类型,ilist2原创 2020-11-04 21:14:50 · 4101 阅读 · 0 评论 -
手写单向队列性能秒杀std::queue
std::queue即单向队列,是一种先入先出的FIFO队列。具有以下特点:只允许从队尾插入元素,从队头删除元素先进先出(First In First Out)不允许在中间部位进行操作一共6个函数front()、back()、push()、pop()、empty()、size(),自己手写实现,也是比较简单的。接下来, 我们就手写实现一个定制的queue队列,然后将其与std::queue性能进行对比。一、IORequestQueue队列类实现IORequestQueue.h#ifnde原创 2020-11-04 18:00:22 · 2174 阅读 · 0 评论 -
CONTAINING_RECORD宏原理与使用详解
先不急着说CONTAINING_RECORD宏,我们从最浅显的代码开始讲解。一、0指针的妙用0指针,即nullptr、NULL,空指针,是不是很常见,一遇到它往往就是segment fault。代码,如下:struct Test{ int a; float b;};Test* pTest = nullptr;int a_value = pTest->a; // segment faultint b_value = pTest->b; // segment fau原创 2020-10-23 17:37:44 · 2918 阅读 · 0 评论 -
C语言实现循环左移和右移
一、win下stdlib.h中的循环移位函数unsigned int _rotl( unsigned int value, int shift);unsigned __int64 _rotl64( unsigned __int64 value, int shift);unsigned int _rotr( unsigned int value, int shift);unsigned __int64 _rotr64( unsigned __int64原创 2020-10-22 21:08:06 · 15752 阅读 · 0 评论 -
利用随机数实现指定概率抽奖
一、随机数与概率的规律假设我们使用随机数生成器,可以产生1-100范围内随机数。那么每次产生的随机数,其值可能是1-100范围内任意一个数,每个数的概率均等。所以可以得出,随机数值V与概率P,有如下规律:数值(V)概率(P)1 <= V <= 100100%V < 1 或 V > 1000%1 <= V <= 5050%50 <= V <= 10050%1 <= V <= 2020%原创 2020-10-17 16:34:12 · 4900 阅读 · 0 评论 -
分享一种高效伪随机数生成算法
我们知道C语言提供了随机数生成,另外Qt也提供了随机数的生成。比如C语言,生成0-19随机数,如下:srand(time(nullptr)); // 从1970-01-01 00:00:00到现在的秒数为随机数种子int val = rand() % 20;Qt生成0-19随机数,如下:qsrand(time(nullptr)); // 从1970-01-01 00:00:00到现在的秒数为随机数种子int val = qrand() % 20;一、高效随机数生成算法另外,在开源项目di原创 2020-10-17 11:23:02 · 1644 阅读 · 0 评论 -
C++11中std::thread线程实现暂停(挂起)功能
一、封装Thread类我们基于C++11中与平台无关的线程类std::thread,封装Thread类,并提供start()、stop()、pause()、resume()线程控制方法。为了让线程在暂停期间,处于休眠,不消耗CPU,我们使用C++11提供的锁和条件变量来实现。std::mutexstd::condition_variableThread.h#ifndef THREAD_H#define THREAD_H#include <thread>#include &原创 2020-09-23 14:29:45 · 17038 阅读 · 4 评论 -
Linux下获取ns级代码执行时间
一、封装计时器类CTimerNs.h#ifndef CTIMERNS_H#define CTIMERNS_H#include <time.h>/** * @brief The CTimerNs class * linux下时间统计类(ns级) */class CTimerNs{public: inline CTimerNs() { clock_gettime(CLOCK_REALTIME, &startTime); }原创 2020-09-22 17:15:29 · 622 阅读 · 0 评论 -
白话内存对齐
内存对齐,这个词,相信大家并不陌生,往往听说对齐有多好多好。那么到底是在对齐什么呢??为什么要对齐,不对齐不行吗?接下来,带大家用最朴实无华的语言,来理解内存对齐。请忽略,以下例子中的部分地址等不合理性,专注于故事本身。一、CPU总线是一只手以32位系统为例,对应的数据总线宽度是32位,其通过数据总线获取内存中的数据。32bit / 8bit = 4byte即,CPU一次性最多只能拿到4个字节数据。那么假设CPU需要获取0x01地址上的一个字节,由于在内存中,每个地址对应一个字节,而CPU原创 2020-09-11 18:30:50 · 485 阅读 · 0 评论 -
Linux下获取us级代码执行时间
如题,对某段代码获取其运行消耗的时间(微秒级别)。一、gettimeofday函数函数原型,如下:int gettimeofday(struct timeval*tv, struct timezone *tz);其参数tv是保存获取时间结果的结构体,参数tz用于保存时区结果:结构体timeval的定义为:struct timeval{ long int tv_sec; // 秒数 long int tv_usec; // 微秒数 };结构体timezone的定义为:原创 2020-08-29 18:32:02 · 1479 阅读 · 0 评论 -
Windows下获取us级代码执行时间
如题,对某段代码获取其运行消耗的时间(微秒级别)。一、涉及到2个系统API函数QueryPerformanceFrequency函数,其原型如下:BOOL QueryPerformanceFrequency( LARGE_INTEGER *lpFrequency);微软帮助文档:https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequencyQu原创 2020-08-29 18:29:20 · 1170 阅读 · 0 评论 -
CPU数据预取对软件性能的影响
一、什么是预取预取是指将内存中的指令和数据提前存放到cache(L1、L2、L3)中,从而加快处理器执行速度。Cache预取可以通过硬件或者软件实现,也就是分为硬件预取和软件预取两类。硬件预取,是通过处理器中专门的硬件来实现的,该硬件监控正在执行程序中请求的指令或数据,识别下一个程序需要的流然后预取到处理器中。软件预取,是通过编译器分析代码然后在程序编译的过程中插入prefetch。这样在执行过程中在指定位置就会进行预取的动作。本文讨论的预取指软件预取。二、使用_mm_prefetch预取原创 2020-07-31 18:52:54 · 5021 阅读 · 0 评论 -
CPU基础知识之Cache介绍
一、什么是CacheCache就是CPU缓存,它是位于CPU和内存之间的临时存储器。CPU在读取数据进行计算的时候,首先是从内部的缓存中查找需要的数据,如果有,可以最短时间最快速度交付CPU。但是如果没有找到,CPU就会提出“要求”经过缓存从内存中读取,再原路返回到CPU进行计算。同时,把这个数据所在的数据也调入缓存,可以使得以后对整块数据的读取都从缓存中进行,不必再调用内存。换句话说,CPU中缓存是为了加快CPU读取数据的速度,也是为了给内存一个缓冲期。因为CPU运算速度太快了,光靠内存读写完全跟不上原创 2020-07-31 17:00:07 · 13784 阅读 · 3 评论 -
linux下设置线程亲和性
linux下线程亲和性主要就是通过pthread_setaffinity_np()函数来完成。首先将线程需要绑定的core编号,添加到一个集合中,然后调用此函数就ok。测试代码如下:#define _GUN_SOURCE#include <unistd.h>#include <pthread.h>#include <sched.h>#include <stdio.h>void *testfunc(void *arg){ cpu_set_t原创 2020-07-26 17:18:57 · 1872 阅读 · 0 评论 -
windows下设置线程亲和性(支持大于64核)
设置线程亲和性,通俗的说法就是将线程绑定到cpu上某一个或多个核上,此处的核是指逻辑核心,非物理核心。物理核心与逻辑核心的关系,如果开启超线程,一般逻辑核心数=物理核心数*2。一、SetThreadAffinityMask微软帮助:https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setthreadaffinitymask函数定义如下:DWORD_PTR SetThreadAffinityMask(HAND原创 2020-07-26 14:54:51 · 10704 阅读 · 10 评论 -
win下线程亲和性概念
微软官方文档:https://docs.microsoft.com/en-us/windows/win32/procthread/multiple-processors 具有多个处理器的计算机通常是为两种体系结构之一而设计的:非统一内存访问(NUMA)或对称多处理(SMP)。 在NUMA计算机中,每个处理器比其他处理器更接近内存的某些部分,使得内存的某些部分的内存访问比其他部分更快。在NUMA模型下,系统试图在接近所用内存的处理器上调度线程。有关NUMA的更多...原创 2020-06-29 19:25:13 · 785 阅读 · 0 评论 -
win下处理器组概念
微软官方文档:https://docs.microsoft.com/en-us/windows/win32/procthread/processor-groups译文如下: 64位版本的Windows 7和Windows Server 2008 R2及更高版本的Windows在一台计算机上支持64个以上的逻辑处理器。此功能在32位版本的Windows上不可用。 具有多个物理处理器的系统或具有多个内核的物理处理器的系统为操作系统提供了多个逻辑处理器。A逻辑处...原创 2020-06-29 19:17:25 · 3038 阅读 · 0 评论 -
win下从NUMA节点分配内存
微软官网链接:https://docs.microsoft.com/zh-cn/windows/win32/memory/allocating-memory-from-a-numa-node?redirectedfrom=MSDN示例代码:#define _WIN32_WINNT 0x0600#include <windows.h>#include <stdlib.h>#include <stdio.h>#include <psapi...原创 2020-06-29 18:02:18 · 1759 阅读 · 0 评论 -
windows平台对NUMA的支持
微软官网链接:https://docs.microsoft.com/en-us/windows/win32/procthread/numa-support译文如下:多处理器支持的传统模型是对称多处理器(SMP)。在这种模型中,每个处理器对内存和输入/输出有平等的访问权。随着处理器数量的增加,处理器总线成为系统性能的一个限制。系统设计人员使用非均匀内存访问(NUMA)来提高处理器速度,而不增加处理器总线上的负载。体系结构是不统一的,因为每个处理器靠近内存的某些部分,而远离内存的其他部分。处理.原创 2020-06-29 17:58:31 · 4472 阅读 · 0 评论 -
如何在内存中执行二进制代码之linux平台
之前写了一篇关于win平台下,从内存执行二进制码的文章,所以此文主要修改自那篇。大家可能会很好奇,我们的任意程序,不就是在内存中执行的二进制机器码吗?不,今天我要说的是,我们如何把实现指定功能的一段二进制机器码,放到我们的程序中,然后在需要的时候,直接调用它。当然,这段代码也有其他用途,故而有了shell code的昵称,参考百度百科:https://baike.baidu.com/item/shellcode/4051847?fr=aladdin思考:我们需要解决以下问题二进制代码从哪里来原创 2020-06-07 21:13:45 · 1715 阅读 · 0 评论 -
如何在内存中执行二进制代码之win平台
大家可能会很好奇,我们的任意exe程序,不就是在内存中执行的二进制机器码吗?不,今天我要说的是,我们如何把实现指定功能的一段二进制机器码,放到我们的程序中,然后在需要的时候,直接调用它。当然,这段代码也有其他用途,故而有了shell code的昵称,参考百度百科:https://baike.baidu.com/item/shellcode/4051847?fr=aladdin思考:我们需要解决以下问题二进制代码从哪里来?c/c++中如何调用它?这些问题,接下来,都会得到解决。不过,我们原创 2020-06-07 17:43:43 · 2723 阅读 · 0 评论 -
shared_ptr智能指针的使用
一、shared_ptr简单说明如果一个实例指针被多个对象使用,而调用者不知道该什么时候释放该实例。那么可以使用shared_ptr来"托管"这个实例指针,当使用它的对象都被释放掉了,这个实例可以自动被释放。可能有点绕,简单地说,就是类A的实例指针pA,被传入对象B、C、D中使用,那么当B、C、D被释放时,也就是不再持有pA时,pA指向的实例被自动释放。shared_ptr的使用与普通指针类似。不过其内部有引用计数,若被引用次数=0,或者shared_ptr被销毁,那么其托管的对象就会被释放。1.s原创 2020-05-10 20:43:08 · 543 阅读 · 0 评论 -
SmartBuffer-让你不再为共享与私有缓存处理逻辑费神
一、带着问题,找思路有这样一个需求,有3个算法类,我们分别称为TestAlgo1、TestAlgo2、TestAlgo3,每个算法可以设置使用buffer类型是共享或私有。补充:共享是指在同类型算法的多个实例中使用同一块buffer,比如若算法TestAlgo1指定为共享buffer,则TestAlgo1的三个实例xx,yy,zz,均使用一块buffer进行读写操作。私有是指每个算法实例,均有自己的buffer。我们应该怎么实现呢?首先我们定义一个内存块buffer类:class Memory原创 2020-05-10 17:58:50 · 650 阅读 · 0 评论 -
利用回调函数消灭大量分支语句if,case
1、背景有这样一个场景,常见的通讯程序中,根据不同的消息类型,调用不同的处理函数。类似于处理登陆、退出登陆、发送消息等类型。上古操作可能会是这样的代码:void dealLogin(){ // ... std::cout << "received login info, do somthing" << std::endl;}void...原创 2020-04-19 18:42:49 · 462 阅读 · 0 评论 -
C++11并发编程(四):原子操作
1、原子操作介绍(1)所谓的原子操作,取的就是“原子是最小的、不可分割的最小个体”的意义,它表示在多个线程访问同一个全局资源的时候,能够确保所有其他的线程都不在同一时间内访问相同的资源。也就是他确保了在同一时刻只有唯一的线程对这个资源进行访问。这有点类似互斥对象对共享资源的访问的保护,但是原子操作更加接近底层,因而效率更高。(2)在以往的C++标准中并没有对原子操作进行规定,我们往往是使用...原创 2020-04-12 15:27:35 · 1196 阅读 · 0 评论 -
C++11并发编程(三):条件变量
1、线程同步中互斥锁存在的问题互斥锁std::mutex是一种最常见的线程间同步的手段,但是在有些情况下不太高效。假设想实现一个简单的消费者生产者模型,一个线程往队列中放入数据,一个线程往队列中取数据,取数据前需要判断一下队列中确实有数据,由于这个队列是线程间共享的,所以,需要使用互斥锁进行保护,一个线程在往队列添加数据的时候,另一个线程不能取,反之亦然。用互斥锁实现如下:#...转载 2020-04-12 14:18:54 · 370 阅读 · 0 评论 -
C++11并发编程(二):互斥锁
1、了解线程的同步和互斥同步是指散步在不同任务之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。最基本的场景就是:两个或两个以上的进程或线程在运行过程中协同步调,按预定的先后次序运行。比如 A 任务的运行依赖于 B 任务产生的数据。 互斥是指散步在不同任务之间的若干程序片断,当某个任务运行其中一个程序片段时,其它任务就不能运...原创 2020-04-12 10:26:10 · 1208 阅读 · 0 评论 -
C++11并发编程(一):线程
1、建立线程thread::join(),函数被调用后,调用它的线程会被block,直到线程执行被完成。以下讲解,主要包括无参、带参、类成员函数作为线程函数。(1)无参函数#include <iostream>#include <thread>using namespace std;void func(){ cout<<"t...原创 2020-04-11 17:49:06 · 435 阅读 · 0 评论 -
头文件中定义数组的问题解决办法
在.h文件中定义了数组并初始化,然后在多个.c文件中使用#include "xxx.h",对.h文件中的数组进行访问时,编译会报错,尽管有#ifndef #define #endif;在定义数组前面加修饰符const也不能解决。解决办法:在定义数组前面加修饰符static,例如static char img_buf[] = {...};原创 2013-09-11 14:59:19 · 11771 阅读 · 5 评论 -
C语言基础
1.Switch(dat)语句dat必须为整型或字符型表达式,不能为浮点型float2.exit()退出程序,准确是结束一个进程,无返回值3.单目运算符结合性为自右向左,&P++,*P++4.(void *)0 == NULL;c语言中指针的大小为4个字节5.printf(“%p\n”, &a); %p格式化输出指针地址6.int a = 10;const int *p1原创 2013-09-11 14:56:25 · 760 阅读 · 0 评论 -
指针与数组
1.char *a[5]; 指针数组char (* a)[5]; 数组指针2. 先声明几个指针放着做例子: 例一: (1)int*ptr; (2)char*ptr; (3)int**ptr; (4)int(*ptr)[3]; (5)int*(*ptr)[4]; 指针的类型 从语法的角度看,你只要把指针声明原创 2013-09-11 14:43:23 · 556 阅读 · 0 评论 -
C语言不太常用的语法
1.register int a; 定义寄存器变量,让编译器把a放到cpu的寄存器中,加快此变量的存取速度,但是也有可能不会被放入cpu寄存器中2.const int a = 3; 伪常量a,具有只读属性。当被定义为局部变量时,a = 10是错误的,变量定义后不能被重新赋值;但是可以通过int *p = (int *)&a; *p = 10,指针方式修改变量的值。当被定义为全局变原创 2013-09-11 14:37:16 · 1007 阅读 · 0 评论