Chromium源码阅读之旅

您所在的位置:网站首页 memcpy不明确 Chromium源码阅读之旅

Chromium源码阅读之旅

2023-03-30 01:03| 来源: 网络整理| 查看: 265

复习指针:一个指针占几个字节?原理是什么呢?为什么呢?总线的类型以及简单功能:指针和指针变量的区别memcpy与memmove区别和实现memcpy的实现:memmove的实现:结构体关于 . 和 ->Handle—句柄模板类泛型继承/派生双冒号单冒号我淦你个枚举类型final关键字宏定义

记一点C++的笔记吧(为了看懂Chromium源码😭😭),毕竟大一学过C,虽然忘了,但是C代码能看懂

复习指针:一个指针占几个字节?原理是什么呢?

不懂的话,就去看B站 郝斌 老师讲的C语言一个指针在32位的计算机上,占4个字节;一个指针在64位的计算机上,占8个字节。

为什么呢?

首先,指针就是地址,地址就是指针。 而地址是内存单元的编号。所以,一个指针占几个字节,等于是一个地址的内存单元编号有多长。我们都知道,在计算机中,CPU不能直接与硬盘进行数据交换,CPU只能直接跟内存进行数据交换。而CPU是通过地址总线、数据总线、控制总线三条线与内存进行数据传输与操作。

问:假如,我们想通过CPU在内存中读取一个数字3,那么是怎样一个操作呢?首先,CPU通过地址总线,在内存中找到数字3的地址;然后,通过控制总线知道该操作是读还是写;最后,通过数据总线,把数字3传输到CPU中。

总线的类型以及简单功能:

地址总线的宽度决定了CPU的寻址能力;控制总线决定了CPU对其他控件的控制能力以及控制方式。数据总线的宽度决定了CPU单次数据传输的传送量,也就是数据传输速度;

我们平时所说的计算机是64位、32位、16位,指的是计算机CPU中通用寄存器一次性处理、传输、暂时存储的信息的最大长度。即CPU在单位时间内(同一时间)能一次处理的二进制数的位数。假如,某计算机的地址总线是32位,那么其一次可以处理的信息是32条,每一条地址总线有0或1两种可能,那么32根地址总线一共有232种可能,也就是其描述的地址空间为0x0000 0000 0000 0000 ~ 232-1。【 我们一般需要32个0或1的组合就可以找到内存中所有的地址,而32个0或1的组合,就是32个位,也就是4个字节的大小,因此,我们只需要4个字节就可以找到所有的数据。所以,在32位的计算机中,指针占4个字节。同理,在64位的计算机中,指针占8个字节。】

同时也可以看出,由于地址总线为32,那么每次寻址的空间为0x0000 0000 0000 0000 ~ 232-1,那么CPU的最大内存为2^32Byte=2^22KB=2^12MB=2^2GB=4GB。而64位,最大内存是2^64Byte。

这里的单位为何又变为了Byte呢?其他知识点:1位=1bit=1比特,表示一个二进制0或1; 1字节(Byte) = 8位=8bit=8比特

数据存储是以“字节”(Byte)为单位,数据传输大多是以“位”(bit,又名“比特”)为单位,一个位就代表一个0或1(即二进制),每8个位(bit,简写为b)组成一个字节(Byte,简写为B),是最小一级的信息单位。

1个英文字母(不分大小写)占一个字节的空间

计算机能够处理的最小单元是 字节 而不是 位。位,是由软件通过位运算符操作的

我们寻址寻的只是起始地址,但是最小单位是字节,即寻得是那个字节的起始地址!所以单位最终是Byte

指针和指针变量的区别

看完郝斌老师C视频的同学,可以看到老师讲的是:一个指针变量占几个字节

指针变量里面存放的是:某一类型的数据的第一个地址值。 也就是地址值占几个字节,指针变量就占几个字节 因此, 一个指针占几个字节 一个地址占几个字节 一个指针变量占几个字节 三种问法等同 不过,严谨些说,该题目改为 一个指针变量占几个字节 更为贴切些

内存地址是内存单元的编号 ;指针就是地址,地址就是指针;指针变量就是存放地址的变量,也可以说,指针变量就是存放指针的变量

例如:int p 中 p 就是指针变量。*需要注意:通常我们叙述时,会把指针变量简称为指针,实际上它们的含义并不一样

memcpy与memmove区别和实现

memcpy与memmove的目的都是将N个字节的源内存地址的内容拷贝到目标内存地址中。

但当源内存和目标内存存在重叠时,memcpy不保证拷贝结果的正确,而memmove能正确地实施拷贝,但这也增加了一点点开销。

memcpy的实现: 当源内存的首地址等于目标内存的首地址时,不进行任何拷贝

当源内存的首地址不等于目标内存的首地址时,实行正向拷贝

memmove的实现:

当源内存的首地址等于目标内存的首地址时,不进行任何拷贝

当源内存的首地址大于目标内存的首地址时,实行正向拷贝当源内存的首地址小于目标内存的首地址时,实行反向拷贝

当拷贝的区域重叠时,若源内存的首地址大于目标内存的首地址,则使用memcpy与memmove拷贝重叠的区域都不会出现问题,内容均可以正确的被拷贝;若源内存的首地址小于目标内存的首地址,则使用memcpy时,源内存中末尾字节内容会被覆盖,导致最后拷贝到目标内存的是已经被覆盖的内容。

551 #ifndef __HAVE_ARCH_MEMCPY552 /**553 * memcpy - Copy one area of memory to another554 * @dest: Where to copy to555 * @src: Where to copy from556 * @count: The size of the area.557 *558 * You should not use this function to access IO space, use memcpy_toio()559 * or memcpy_fromio() instead.560 */561 void *memcpy(void *dest, const void *src, size_t count)562 {563 char *tmp = dest;564 const char *s = src;565566 while (count--)567 *tmp++ = *s++;568 return dest;569 }570 EXPORT_SYMBOL(memcpy);571 #endif572573 #ifndef __HAVE_ARCH_MEMMOVE574 /**575 * memmove - Copy one area of memory to another576 * @dest: Where to copy to577 * @src: Where to copy from578 * @count: The size of the area.579 *580 * Unlike memcpy(), memmove() copes with overlapping areas.581 */582 void *memmove(void *dest, const void *src, size_t count)583 {584 char *tmp;585 const char *s;586587 if (dest

一般情况下用“.”,只需要声明一个结构体。格式是,结构体类型名+结构体名。然后用结构体名加“.”加域名就可以引用域 了。因为自动分配了结构体的内存。如同 int a;一样。

而用“->”,则要声明一个结构体的指针(或者 &结构体变量名 作为函数实参, 相应的形参当然是指针类型啦),还要手动开辟一个该结构体的内存,然后把返回的指针给声明的结构体指针,才能用“->”正确引用。否则内存中只分配了指针的内存,没有分配结构体的内存,导致想要的结构体实际上是不存在。这时候用“->”引用自然出错了,因为没有结构体,自然没有结构体的域了。

此外,(*a).b 等价于 a->b。“.”一般情况下读作 “的”。“->”一般读作 “xxx指向的结构体 的 xxxxx成员变量”。[

](https://blog.csdn.net/faihung/article/details/79190039)

Handle—句柄

所谓句柄实际上是一个数据,是一个Long (整长型)的数据。

句柄是WONDOWS用来标识被应用程序所建立或使用的对象的唯一整数,WINDOWS使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等。WINDOWS句柄有点象C语言中的文件句柄。 从上面的定义中的我们可以看到,句柄是一个标识符,是拿来标识对象或者项目的,它就象我们的姓名一样,每个人都会有一个,不同的人的姓名不一样,但是,也可能有一个名字和你一样的人。从数据类型上来看它只是一个16位的无符号整数。应用程序几乎总是通过调用一个WINDOWS函数来获得一个句柄,之后其他的WINDOWS函数就可以使用该句柄,以引用相应的对象。如果想更透彻一点地认识句柄,我可以告诉大家,句柄是一种指向指针的指针。我们知道,所谓指针是一种内存地址。应用程序启动后,组成这个程序的各对象是住留在内存的。如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址访问对象。但是,如果您真的这样认为,那么您就大错特错了。我们知道,Windows是一个以虚拟内存为基础的操作系统。在这种系统环境下,Windows内存管理器经常在内存中来回移动对象,依此来满足各种应用程序的内存需要。对象被移动意味着它的地址变化了。如果地址总是如此变化,我们该到哪里去找该对象呢?**为了解决这个问题,Windows操作系统为各应用程序腾出一些内存储地址,用来专门登记各应用对象在内存中的地址变化,而这个地址(存储单元的位置)本身是不变的。Windows内存管理器在移动对象在内存中的位置后,把对象新的地址告知这个句柄地址来保存。这样我们只需记住这个句柄地址就可以间接地知道对象具体在内存中的哪个位置。这个地址是在对象装载(Load)时由系统分配给的,当系统卸载时(Unload)又释放给系统。****句柄地址(稳定)→记载着对象在内存中的地址————→对象在内存中的地址(不稳定)→实际对象** 本质:WINDOWS程序中并不是用物理地址来标识一个内存块,文件,任务或动态装入模块的,相反的,WINDOWS API给这些项目分配确定的句柄,并将句柄返回给应用程序,然后通过句柄来进行操作。

但是必须注意的是程序每次从新启动,系统不能保证分配给这个程序的句柄还是原来的那个句柄,而且绝大多数情况的确不一样的。假如我们把进入电影院看电影看成是一个应用程序的启动运行,那么系统给应用程序分配的句柄总是不一样,这和每次电影院售给我们的门票总是不同的一个座位是一样的道理。

模板类

template // 模板声明T add(T a,T b) { return a+b; } // 注意形参和返回值的类型

1) 类模板不是真正的类,它只是C++编译器生成具体类的一个模子。2) 类模板可以设置默认模板实参。

泛型

跟java,ts写法差不多吧? 主要功能肯定是一致的

继承/派生// 基类class Animal { // eat() 函数 // sleep() 函数};//派生类class Dog : public Animal { // bark() 函数};

双冒号

双冒号(::)用法 —— ::指作用域运算符,或者叫作用域限定符。(1)表示“域操作符”例:声明了一个类A,类A里声明了一个成员函数void f(),但没有在类的声明里给出f的定义,那么在类外定义f时,就要写成void A::f(),表示这个f()函数是类A的成员函数。(2)直接用在全局函数前,表示是全局函数 // 也可以局部变量使用同名的全局变量例:在VC里,你可以在调用API 函数里,在API函数名前加::(3)表示引用成员函数及变量,作用域成员运算符例:System::Math::Sqrt() 相当于System.Math.Sqrt()(4)程序内部有和API函数同名的函数::GetWindowRect(gameh,&r1)这样写上::就会明确调用外部API中GetWindowRect函数::在这里表是全局函数,是API里的函数,但是MFC用类封装了这些API,而且函数名和API函数一样。在类里面使用时如果不加::就会被认为是该类里面的相应函数,如果加上::则表示系统的API函数,一般说来系统API函数都要多一个参数。

单冒号 类名冒号后面用来定义类的继承类名冒号后面用来定义类的继承用法3:表示结构内的位域(该变量占几个bit空间) 我淦你个枚举类型一开始不知道它声明后即有默认值,搞得我没读懂chromium对于变量声明的几个关键的定义一,枚举类型的说明枚举数据类型是一种由程序员定义的数据类型,其合法值是与它们关联的一组命名整数常量。

之所以被称为枚举类型,就是因为命名常量是作为数据类型定义的一部分而枚举或列出的以下是枚举类型声明的示例:1 enum {};关键字enum:说明接下来定义的是一个枚举类型。类型名字:指明此处定义的枚举类型的名字。 常量表:由枚举常量(或称枚举成员)构成。枚举常量表列出枚举类型所有可能的取值,各枚举常量之间用“,”间隔,且各枚举常量必须不同。

例如(解引题):1 enum Weekday{SUN,MON,TUE,WED,THU,FRI,SAT};//定义枚举类型weekday枚举常量只能以标识符形式表示,而不能是整型、字符型等文字常量。例如,以下定义非法1 enum book{‘a’,’b’,’c’,’d’};//枚举类型不能是字符常量 2 3 enum year{1998,1999,2010,2012};//枚举常量不能是整形常量二,枚举类型的赋值1.枚举类型在声明之后具有默认值。默认从0开始,依次为0,1,2,3……例如(解引题):1 enum Weekday{SUN,MON,TUE,WED,THU,FRI,SAT};//定义枚举类型weekday 2 //SUN=0,MON=1,依次为0,1,2,3…..2.同时也可以在声明中直接赋值。它们必须是整数。枚举变量相当于整型变量的一个子集例如(解引题):1 enum Weekday{SUN=7,MON=2,TUE,WED,THU,FRI,SAT}; 2 //定义SUN=7,MON=2,则后面的值在前面值的基础上依次加1,即TUE=3,WED=4……1 enum weekday{SUN=1.1,MON=1.2,……};//枚举变量赋值只能是整数,相当于整型变量的一个子集,此语句非法

3.对枚举元素按常量处理,但不能对它们直接赋予常量值。例如(解引题):1 enum Weekday{SUN,MON,TUE,WED,THU,FRI,SAT};//定义枚举类型weekday 2 SUN=0;//SUN是枚举元素,不能赋值,此语句非法若将整数值赋给枚举变量需要进行强制类型转换:值前面加(类型名)例如(解引题):enum Weekday{SUN,MON,TUE,WED,THU,FRI,SAT};//定义枚举类型weekday SUN=(Weekday)7;//在值前面加(类型)是常用的强制类型转换方法

final关键字 final关键字修饰类

用来修饰类,让该类不能被继承,理解:使得该类终结!

class XiaoMi {public: XiaoMi(){}};class XiaoMi2 final : public XiaoMi { XiaoMi2(){}};class XiaoMi3 : public XiaoMi2 { //❌,不能把XiaoMi2作为基类};

final关键字只能放在类名的后面!

final关键字修饰虚函数

用来修饰类的虚函数,使得该虚函数在子类中,不能被重写,理解:使得该功能终结!

class XiaoMi {public: virtual void func() final;};void XiaoMi::func() { //不需要再写final cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3