函数指针

Linux 内核红黑树分析

六月ゝ 毕业季﹏ 提交于 2019-12-02 12:15:13
内核版本为 linux4.2.1 本文主要从红黑树的代码实现入手,来讨论linux内核中是如何实现红黑树的(主要是插入和删除操作),其中涉及到的函数有三个__rb_insert __rb_erase_augmented ____rb_erase_color,本文将用图示的方式解析这三个函数。 1.红黑树性质 1.节点是红色或者黑色 2.根节点是黑色 3.所有叶子节点(null)都为黑色 4.红色节点的子节点都是黑色 5.从根节点到叶子节点所有路径上黑色节点数相同 2.基础 2.1 节点结构 struct rb_node { unsigned long __rb_parent_color; struct rb_node *rb_right; struct rb_node *rb_left; } __attribute__((aligned(sizeof(long)))); 不难看出 rb_left 和 rb_right 是该节点左右子节点的指针,结构体后面的__attribute__((aligned(sizeof(long))))让这个结构体按照4字节对齐(64位是8字节)。 __rb_parent_color这个参数名字有点奇怪,父亲的颜色?啥意思?不过当我们理解了这个参数的意义之后发现还真就应该叫这个名字。这个名字的意思其实是 “父亲和颜色”,它即代表了父节点的地址

STL源码剖析——序列式容器#2 List

妖精的绣舞 提交于 2019-12-02 11:49:32
  list就是链表的实现,链表是什么,我就不再解释了。list的好处就是每次插入或删除一个元素,都是常数的时空复杂度。但遍历或访问就需要O(n)的时间。   List本身其实不难理解,难点在于某些功能函数的实现上,例如我们会在最后讨论的迁移函数splice()、反转函数reverse()、排序函数sort()等等。 list的结点   设计过链表的人都知道,链表本身和链表结点是不一样的结构,需要分开设计,这里的list也不例外,以下是STL list的结点结构: 1 template <class T> 2 struct __list_node { 3 typedef void* void_pointer; 4 void_pointer next; 5 void_pointer prev; 6 T data; 7 };   从结点结构可以看出,list是一个双向链表,有指向前一结点的prev指针,指向下一结点的next指针。 list的迭代器   显然,list的迭代器本身是什么类型早已由其本身的数据结构所决定,list的双向链表,不支持随机存取,只能是双向迭代器(Bidirectional Iterators)。另外,list的迭代器应该支持正确的递增、递减、取值、成员取用等操作。   以下是list迭代器的源码: 1 template<class T, class Ref,

虚函数以及纯虚函数

天涯浪子 提交于 2019-12-02 11:27:30
   多态性 是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异,而采用不同的策略。   虚函数和纯虚函数都是实现多态的重要方法。本文就这两种方法进行分析以及比较 1、虚函数 在基类中声明为 virtual 并在一个或者多个派生类被重新定义的成员函数 语法规则: virtual 函数返回类型 函数名(参数表) {函数体} 语法分析:虚函数的声明和定义和普通的成员函数一样,只是在返回值之前加入了关键字virtual。      在基类当中定义了虚函数,可以再子类中定义和基类中相同函数名、相同参数、相同返回值和不同实现体的虚函数      定义为虚函数是为了让 基类函数的指针或者引用来指向子类。 #include<iostream> using namespace std; class A { public: void fun() { cout << "A::fun()..." << endl; } }; class B :public A { public: void fun() { cout << "B::fun()...." << endl; } }; int main() { A *a = new A; //A类指针指向A类对象 a->fun(); A *b = new B; //A类指针指向B类 对象 b->fun(); delete a;

c/c++总结

浪尽此生 提交于 2019-12-02 10:47:13
1. 0X0 0x0地址是NULL 2. Gdb调试子进程 1.set follow-fork-mode <parent/child> 这条命令可以用于在调试父进程或是子进程的模式之间进行切换。例如在 fork 函数执行之前执行 set follow-fork-mode child, 当 fork 执行后,设定在子进程上的断点将会有效,而父进程上的断点此时无效;反之依然。缺省 gdb 是调试主进程的。 2.attach<pid> GDB 有附着( attach )到正在运行的进程的功能,即 attach <pid> 命令。因此我们可以利用该命令 attach 到子进程然后进行调试。 3. Gdb调试nginx 多进程调试 #sudo gdb –q (gdb)shell ./nginx 如果只是gdb ./nginx 那么启动nginx还是单进程 4. Linux内核模块编写和makeFile编写 hello.c内容: #include <linux/module.h> #include <linux/init.h> static int hello_init(void) { printk( KERN_ALERT " hello world enter \n"); return 0; } static void hello_exit(void) { printk(KERN_ALERT

Keithee Explorer

谁都会走 提交于 2019-12-01 21:54:07
本章学习如何控制类类型对象在拷贝、赋值、移动和销毁时应该做什么。 一个类定义五种特殊的成员函数来控制对象的拷贝、移动、赋值和销毁操作。他们分别是拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值函数和析构函数。 拷贝、赋值与销毁 拷贝构造函数 如果构造函数的第一个参数是自身对象的引用,而且其他额外参数都有默认值,则该构造函数是拷贝构造函数。 12345 class {public: Foo(); Foo(const Foo&);} 拷贝构造函数会在几种情况下被隐式地使用,所以不应该是 explicit 。 合成拷贝构造函数 如果我们没有定义一个拷贝构造函数,则编译器会为我们定义一个。编译器将类内的每个非 static 成员拷贝到正在创建的对象中。对于类类型的成员,则使用其拷贝构造函数来拷贝。 123456789 class Sales_data{public: Sales_data(const Sales_data&);private: string bookNo; int units_sold; double revenue;} 现在我们可以理解直接初始化和拷贝初始化的真正区别了,也就是说直接初始化是一个构造函数参数匹配的过程,而拷贝初始化要求我们将右侧的运算对象拷贝到左侧的对象中去,有时候还要求类型转换。 拷贝初始化不仅发生在使用 = 运算符时,还发生在以下情况:

C语言字符串操作小结

狂风中的少年 提交于 2019-12-01 16:22:41
1)字符串操作 strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 strcat(p, p1) 附加字符串 strncat(p, p1, n) 附加指定长度字符串 strlen(p) 取字符串长度 strcmp(p, p1) 比较字符串 strcasecmp忽略大小写比较字符串 strncmp(p, p1, n) 比较指定长度字符串 strchr(p, c) 在字符串中查找指定字符 strrchr(p, c) 在字符串中反向查找 strstr(p, p1) 查找字符串 strpbrk(p, p1) 以目标字符串的所有字符作为集合,在当前字符串查找该集合的任一元素 strspn(p, p1) 以目标字符串的所有字符作为集合,在当前字符串查找不属于该集合的任一元素的偏移 strcspn(p, p1) 以目标字符串的所有字符作为集合,在当前字符串查找属于该集合的任一元素的偏移 * 具有指定长度的字符串处理函数在已处理的字符串之后填补零结尾符 2)字符串到数值类型的转换 strtod(p, ppend) 从字符串 p 中转换 double 类型数值,并将后续的字符串指针存储到 ppend 指向的 char* 类型存储。 strtol(p, ppend, base) 从字符串 p 中转换 long 类型整型数值,base 显式设置转换的整型进制

【TencentOS tiny】深度源码分析(2)——调度器

百般思念 提交于 2019-12-01 13:43:37
温馨提示:本文不描述与浮点相关的寄存器的内容,如需了解自行查阅(毕竟我自己也不懂) 调度器的基本概念 TencentOS tiny 中提供的任务调度器是基于优先级的全抢占式调度,在系统运行过程中,当有比当前任务优先级更高的任务就绪时,当前任务将立刻被 切出 ,高优先级任务 抢占 处理器运行。 TencentOS tiny 内核中也允许创建相同优先级的任务。相同优先级的任务采用时间片轮转方式进行调度(也就是通常说的分时调度器),时间片轮转调度仅在当前系统中 无更高优先级就绪任务 的情况下才有效。 为了保证系统的实时性,系统尽最大可能地保证高优先级的任务得以运行。任务调度的原则是一旦任务状态发生了改变,并且当前运行的任务优先级小于优先级队列中任务最高优先级时,立刻进行任务切换(除非当前系统处于中断处理程序中或禁止任务切换的状态)。 调度器是操作系统的 核心 ,其主要功能就是 实现任务的切换 ,即从就绪列表里面 找到 优先级最高的任务,然后去 执行 该任务。 启动调度器 调度器的启动由 cpu_sched_start 函数来完成,它会被 tos_knl_start 函数调用,这个函数中主要做两件事,首先通过 readyqueue_highest_ready_task_get 函数获取当前系统中处于最高优先级的就绪任务,并且将它赋值给指向当前任务控制块的指针 k_curr_task

GO代码风格指南 Uber Go (转载)

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-01 09:35:00
原文地址: https://github.com/uber-go/guide/blob/master/style.md 译文出处: https://github.com/uber-go/guide 本文永久链接: https://github.com/gocn/translator/blob/master/2019/w38_uber_go_style_guide.md 译者: 咔叽咔叽 校对者: fivezh , cvley 目录 介绍 指南 接口的指针 接收者和接口 零值 Mutexes 是有效的 复制 Slice 和 Map Defer 的使用 channel 的大小是 1 或者 None 枚举值从 1 开始 Error 类型 Error 包装 处理类型断言失败 避免 Panic 使用 go.uber.org/atomic 性能 strconv 优于 fmt 避免 string 到 byte 的转换 代码样式 聚合相似的声明 包的分组导入的顺序 包命名 函数命名 别名导入 函数分组和顺序 减少嵌套 不必要的 else 顶层变量的声明 在不可导出的全局变量前面加上 _ 结构体的嵌入 使用字段名去初始化结构体 局部变量声明 nil 是一个有效的 slice 减少变量的作用域 避免裸参数 使用原生字符串格式来避免转义 初始化结构体 在 Printf 之外格式化字符串 Printf

给单片机写个回调函数怎么样

余生颓废 提交于 2019-12-01 09:22:14
一,弄个串口回调 (实际上就是函数指针...) void(*UsartCallBack)(char data);//定义一个函数指针变量 void UsartCallBackReg(void* Back) { UsartCallBack = Back;//把传过来的指针赋值给 UsartCallBack } USART_C_ void(*UsartCallBack)(char data); void UsartCallBackReg(void* Back); 实际上就是定义了一个 void(*UsartCallBack)(char data);//定义一个函数指针变量 然后我把一个函数指针赋值给他 他呢在串口里面调用!!!! 其实直接可以 测试: 然后呢,写个看着有点水平的 typedef void(*UsartCallBack)(char data);//定义一个函数指针类型 UsartCallBack void UsartCallBackReg(UsartCallBack Back); UsartCallBack CallBack;//定义一个无返回值,带一个参数的函数指针变量 void UsartCallBackReg(UsartCallBack Back) { CallBack = Back; } 然后主函数 测试 来源: https://www.cnblogs.com

C++继承和多态

你说的曾经没有我的故事 提交于 2019-12-01 08:44:42
C++继承和多态 继承和派生 C++ 中的继承是类与类之间的关系, 继承(Inheritance) 可以理解为一个类从另一个类获取成员变量和成员函数的过程。 派生(Derive) 和继承是一个概念, 被继承的类称为父类或基类,继承的类称为子类或派生类。“子类”和“父类”通常放在一起称呼,“基类”和“派生类”通常放在一起称呼 当你创建的新类与现有的类相似 当你需要创建多个类,它们拥有很多相似的成员变量或成员函数时,使用继承。可以将这些类的共同成员提取出来,定义为基类,然后从基类继承 class Student: public People 继承的一般语法为: class 派生类名:[继承方式] 基类名{ 派生类新增加的成员 }; 继承方式: 包括 public(公有的)、private(私有的)和 protected(受保护的),此项是可选的,如果不写,那么默认为 private。 C++三种继承方式 继承方式 限定了基类成员在派生类中的访问权限,包括 public(公有的)、private(私有的)和 protected(受保护的)。此项是可选项,如果不写,默认为 private(成员变量和成员函数默认也是 private) public、protected、private 指定继承方式 1) public继承方式 基类中所有 public 成员在派生类中为 public 属性;