《深入理解计算机系统(CSAPP)》第3章 程序的机器级表示 - 学习笔记
写在前面的话:此系列文章为笔者学习CSAPP时的个人笔记,分享出来与大家学习交流,目录大体与《深入理解计算机系统》书本一致。因是初次预习时写的笔记,在复习回看时发现部分内容存在一些小问题,因时间紧张来不及再次整理总结,希望读者理解。
《深入理解计算机系统(CSAPP)》第3章 程序的机器级表示 - 学习笔记_友人帐_的博客-CSDN博客
《深入理解计算机系统(CSAPP)》第5章 优化程序性能 - 学习笔记_友人帐_的博客-CSDN博客
《深入理解计算机系统(CSAPP)》第6章 存储器层次结构 - 学习笔记_友人帐_的博客-CSDN博客
《深入理解计算机系统(CSAPP)》第7章 链接- 学习笔记_友人帐_的博客-CSDN博客
《深入理解计算机系统(CSAPP)》第8章 异常控制流 - 学习笔记_友人帐_的博客-CSDN博客
《深入理解计算机系统(CSAPP)》第9章虚拟内存 - 学习笔记_友人帐_的博客-CSDN博客
第三章 程序的机器级表示
1. 代码编译过程
gcc -Og -o hello source1.c source2.c ...gcc -Og -S -fno-if-conversion source.c // 优化等级低,便于理解
注:①-Og
为代码优化等级;②-o
表示生成可执行文件,-s
可以生成汇编代码;③生成实际可执行的代码需要对一组目标代码文件运行链接器,而这一组目标代码文件中必须含有一个main函数;④有时会在末尾(return后)有90 nop
指令,目的是为了使函数代码变为16字节,使得存储器能更好地放置下一个代码块,提高性能。
源代码转化为可执行代码:
①C预处理器:扩展源代码,插入所有用#include命令指定的文件,并扩展所有#define声明指定的宏;
②编译器:生成源文件的汇编代码,后缀.s;
③汇编器:将汇编代码转化为二进制目标代码文件,后缀.o;
④链接器:将目标代码文件与实现库函数的代码合并,填入全局值的地址,生成可执行代码文件。
GDB调试指令
2. 反汇编
反汇编:将可执行二进制文件翻译为汇编语言
objdump -d target.o
objdump -S target.o > target.txt (在反汇编中加入C代码,且重定向输出到target.txt)
cat target.txt 查看
3. 汇编相关(AT&T格式)
3.1 伪指令
所有以.
开头的指令都是指导汇编器和链接器工作的伪指令;
3.2 汇编代码后缀
3.3 寄存器
(1)通用寄存器:
规则:生成1字节和2字节数字的指令会保持剩下的字节不变;生成4字节数字的指令会把高位4个字节置为0。
(2)段寄存器:
(3)指令指针寄存器EIP/PC
(4)EFLAGS寄存器
(5)系统寄存器
(6)浮点单元FPU
3.4 操作数指示符
操作数类型:
①立即数:用$
符号表示,代表常数值;
②寄存器:直接访问寄存器的值;
③内存寻址: I m m ( R b , R i , S ) = I m m + R b + R i ∗ S Imm(R_b,R_i,S)=Imm+R_b+R_i*S Imm(Rb,Ri,S)=Imm+Rb+Ri∗S,其中, I m m Imm Imm表示立即数偏移, R b R_b Rb表示基址寄存器, R i R_i Ri表示变址寄存器, S S S为比例因子,仅能取值1,2,4,8。计算得到的为一个地址,相当于解引用操作。
3.5 mov指令
注意:
①两个操作数不能同时指向内存位置。
②寄存器部分的大小必须与指令最后一个字符(‘b’,‘w’,‘l’,‘q’)指定的大小匹配。大多数情况,MOV指令只会更新目的操作数指定的寄存器字节或内存位置,但当movl指令以寄存器作为目的时,会把该寄存器的高4位设置为0(任何为寄存器生成32位值的指令都会把该寄存器的高位部分置为0)。
③不要给%rsp赋值(系统保留)。
扩展 - 零扩展(movz)、符号扩展(movs)+大小指示符(源,目的)
条件传送
cmov
cc
src, dst
cc
表示条件,使用EFLAGS中的条件码实现条件判断对于无符号数,使用a,b,e,b,c分别表示大于、小于、等于、否定、进位
对于有符号数,使用g,l,e,n,o分别表示大于、小于、等于、否定、溢出
3.6 栈操作
栈向下增长,栈顶为低地址。
指令:
示意:
3.7 算术和逻辑操作
注意:
leaq并不是取源S的地址放入寄存器D,而是将有效地址放入,例如若%rdx值为x,则指令leap 7(%rdx, %rdx, x) %rax
将寄存器%rax的值设置为5x+7
特殊的算数操作:八字
3.8 调试常用指令
- 编译:./mak64 try64
- 调试:gdb ./try64
- 设置断点:b _start
- 打开源代码窗口:layout src
layout split - 上方源代码,下方汇编
打开寄存器观察窗口:tui r g r表示register,g表示general,通用寄存器
运行:r
在断点处停止后,单步运行:n
4. IA32的内存管理
4.1 实地址模式
实地址模式:存储内容为真实物理地址。
内存分段:16位地址线不能直接表示20位地址,采用内存分段方式,使用两个16位地址来表示。表示为段地址:段内偏移量
;约定段地址低4为为0,便可以用16位地址表示段地址,如此将内存空间划分为64KB的段。而实际地址可以采用实际地址 = 段地址0 + 段内偏移量
计算得到(段地址后补 0 16 0_{16} 016)。
4.2 保护模式
将段描述符(8字节,段的相关信息)在段描述符表中的索引值存放在段寄存器(2字节)中。而在段描述符表中的每一行(每一个段描述符),都保存了段的相关参数、访问权限等信息。
GDT(全局描述符表)和LDT(局部描述符表)都用来存放各种描述符,例如段描述符,但这掩盖不了它们也是内存段的事实。简单地讲,他们也是段。但是,因为它们用于系统管理,故称为系统的段或者系统段。GDT是唯一的,整个系统中只有一个,所以只需要用GDTR寄存器(CPU中)存放其线性基地址和段界限即可。其中存储了操作系统使用的代码段、数据段、堆栈段的描述符以及各个程序的LDT段;但LDT不同,每个程序有一个独立的LDT,存放了对应程序的代码段、数据段、堆栈段的描述符等信息。当要使用这些LDT时,可以用它们的选择子来访问GDT,将LDT描述符加载到LDTR寄存器。
全局描述符表寄存器GDTR(48位)指向GDT在内存中的地址。局部描述符表寄存器LDTR(16位)指向LDT段在GDT中的索引。
在段选择器(保护模式下的段寄存器)中:
(1)平坦分段模式
而在段描述符表中:(16进制)所有段被映射到32位物理地址空间,程序至少分为代码段和数据段两个段。
全局描述符表GDT:
基址(32位)指向段的起始地址(图示中指向0000 0000,很低的地址空间为操作系统所用);
界限指该段的长度,其中,0040是相对值,要在后方加上000(乘以4k),即0040 000
,也说明了段的大小都是4k的倍数。
(2)多段模式
局部描述符表LDT:
保护模式下的段寻址总结:
(3)内存分页
5. 控制(条件、循环、分支)
5.1 条件码
CF
:进位标志。最高有效位有进位(无符号溢出)置为1,否则置0。
ZF
:零标志。最近的操作得出的结果为0。
SF
:符号标志。最近的操作得到的结果为负数。
OF
:溢出标志。最近的操作导致一个补码溢出(正溢出或负溢出)
除了leaq指令,其余算术和逻辑操作都伴随着进位标志的设置。
还有一些指令只用于设置条件吗而不改变任何其他寄存器。
SET指令:可以通过条件码的组合来进行各种条件操作(指令的后缀表示不同的条件而不是操作数大小)。目的操作数是低位单字节寄存器元素之一,或是一个字节的内存位置,指令会将这个字节设置为0或1。
cmp指令
cmpq src1, src2
计算src2-src1的值和0比较,仅用结果设置条件码,而不改变目的操作数。
test指令
testq src2, src1
根据src2 & src1 的数值来设置条件码,结果并不保存,通常将其中一个操作数看作是一个掩码。
5.2 跳转指令jump
jump指令会导致执行切换到程序中一个全新的位置。在汇编中,这些跳转的目的地通常用一个标号(label)指明。
直接跳转:jmp .L1 直接跳转到L1标号位置
间接跳转:jmp *%rax 以%rax中的值作为读地址,从内存中读出跳转目标
注:跳转条件为1表示无条件跳转。
跳转指令的编码
PC相对跳转
绝对地址跳转
5.3 用条件控制来实现条件分支
将if转化为goto类型,直接对应于汇编。
if-else的通用转换模板
// if-else版本
if (test-expr)then-statement
elseelse-statement// goto版本t = test-expr;if (!t)goto false;then-statementgoto done;
false:else-statement
done:
使用数据的条件转移来实现条件分支的好处:
(将未知的跳转转换为已知的计算,消除不确定性)
可以使得CPU的流水线中充满了待执行的指令,避免条件预测逻辑(猜测每条跳转指令是否会执行)预测错误而导致浪费CPU的时钟周期,以提高流水线性能。
条件传送指令:
5.4 循环
用条件测试和跳转组合起来实现循环(do-while、while、for)
// do-while通用形式
dobody-statementwhile (test-expr);// goto形式
loop:body-statementt = test-expr;if (t)goto loop;/* ----------------- */
// while 通用形式
while (test-expr)body-statement// while goto形式1 - 跳转到中间goto test;
loop:body-statement
test:t = test-expr;if (t)goto loop;// while goto形式2 - guarded-do
// 先翻译为do-while,再翻译为goto
t = test-expr;
if (!t)goto done;
loop:body-statementt = test-expr;if (t)goto loop;
done:/* ----------------- */
// for 通用形式
for (init-expr; test-expr; update-expr)body-statement// for转化为while
init-expr;
while (test-expr) {body-statementupdate-expr;
}
5.5 switch语句
连续性较好的switch语句用跳转表,不好的用决策树(一堆if else)
switch使用跳转表(一个数组),表项 i i i是一个代码段的地址,这个代码段实现当switch索引值等于 i i i时程序所执行的指令。当switch情况比较多时(>4),并且值的范围跨度比较小时,就会使用跳转表。跳转表的优点是执行语句的时间与情况数量无关。
跳转表对重复情况的处理就是简单地使用相同的代码标号,而对于缺失的情况的处理就是使用默认情况的标号(loc_def)
6. 函数(过程)
6.1 过程机制
**传递控制:**调用时转到调用过程代码的起始位置,结束时回到返回点。
**传递数据:**过程参数与返回值的传递。
**内存管理:**过程运行期间申请内存,返回时解除分配。
该机制全部由机器指令实现。
6.2 栈
栈的结构:
注意:①%rsp始终指向栈顶元素的位置。②向低地址生长。
栈的操作
入栈指令
pushq src
从src取操作数 → 将%rsp减8 → 将操作数写到%rsp指向的位置
出栈指令
popq dst
从%rsp中保存的地址处读取数值 → 将%rsp加8 → 将数值保存到dst(dst必须为寄存器或内存操作数)
6.3 过程控制流
过程调用
call func_label
执行操作:
①将返回地址入栈(返回地址即为紧随call指令的下一条指令的地址)
②跳转到func_label(函数名字就是函数代码段的起始地址)
过程返回
ret
执行操作:
从栈中弹出返回地址,放入%rip里(pc)
参数传递
返回值:%rax
局部变量:仅在需要时申请栈空间
6.4 栈帧
栈的分配单位为帧,保存单个过程实例的状态数据(参数、局部变量、返回地址等)
管理:进入过程时申请空间(生成代码,构建栈帧,包括call指令产生的push操作),返回时解除申请(结束代码,清理栈帧,包括ret指令产生的pop操作)
寄存器保存约定
寄存器组是唯一被所有过程共享的资源,必须确保当一个过程调用另一个过程时,被调用者不会覆盖调用者稍后会使用的寄存器值。
①调用者保存Caller Saved
调用者在调用前,在它的栈帧中保存临时值(寄存器)。
②被调用者保存Callee Saved
被调用者要先在自己的栈帧中保存,然后再使用寄存器。返回到调用者之前,恢复这些保存的值。
一个过程运行的示例
long caller()
{long arg1 = 534;long arg2 = 1057;long sum = swap_add(&arg1, &arg2);long diff = arg1 - arg2;return sum * diff;
}
对应汇编代码:
7. 数组
C语言可以产生指向数组中元素的指针,并对这些指针进行运算。在机器代码中,这些指针会被翻译成地址计算。
7.1 数组规则
T A[N];
来声明数组(数据类型T,整型常数N)。会在内存中分配一个L·N字节的连续空间(L为数据类型T的字节大小),用A来作为指向数组开头的指针的标识符。数组元素i会被存放在地址 x A + L ⋅ i x_A+L·i xA+L⋅i的地方。
7.2 指针运算
7.3 二维数组
8. 结构体和联合
8.1 结构体
结构体的所有字段都存放在内存中一段连续的区域内,而指向结构体的指针就是结构体第一个字节的地址。使用字段相对于起始地址的偏移量来维护各个字段的信息。
字段的顺序必须与声明一致,即便其他顺序能使得内存更加紧凑也不行。
由编译器来决定总的尺寸和和字段的位置。
对齐
对齐后的数据:基本数据类型需要K字节,地址必须是K的倍数。
对其数据的动机:内存按4字节或8字节(对齐的)块来访问(4\8取决于系统),当一个数据跨越2个页面时,虚拟内存比较棘手,不能高效地装载或存储跨越四字边界的数据。
编译器在结构体中插入空白,以确保字段的正确对齐。
结构体内部:满足每个元素的对齐要求。
结构体整体的对齐存放:
K = 所有元素的最大对齐要求值
则起始地址和结构体长度必须是K的倍数。
空间的节省:大尺寸数据类型在前。
8.2 联合
允许以多种类型来引用一个对象,用不同的字段来引用相同的内存块。一个联合的总的大小等于它最大字段的大小。若一个数据结构中的两个不同字段的使用是互斥的,那么将这两个字段声明为联合的一部分会减小分配空间的总量。
访问位模式
联合可以用来访问不同数据类型的位模式。在联合中,以一种数据类型来存储联合中的参数,又以另一种数据类型来访问,结果是他们会具有一样的位表示,包括符号位字段、指数和尾数。
此时字节顺序问题变得很重要,在小端与大端机器中对相同的位模式解读不同。
9. 浮点数
寄存器
YMM是256位,32字节
XMM是128位,16字节
支持操作
①标量操作:单精度/双精度
②SIMD操作:单指令多数据操作,允许多个操作以并行模式执行,对多个不同的数据并行执行同一个操作。
内存引用
参数传递:浮点型参数用YMM\XMM寄存器
使用不同的mov指令在YMM\XMM寄存器之间、或内存和YMM\XMM寄存器之间传送数值。
10.高级主题
10.1 理解指针
-
每个指针都对应一个类型
通常如果对象类型位T,则指针的类型为T*
特殊的void *类型代表通用指针,可以通过显式强转或者赋值等隐式强转来将其转换成一个有类型的指针。
-
每个指针都有一个值
这个值是某个指定类型的对象的地址,特殊的NULL(0)值表示该指针没有指向任何地方。
-
指针用’&'运算符创建
对应于机器代码的leaq指令
-
数组与指针紧密联系
一个数组的名字可以像一个指针变量一样引用,但是不能修改。数组引用(a[3])与指针运算和间接引用(*(a+3))有一样的效果。
-
指针强转
将指针从一种类型强制转换成另一种类型,只改变它的类型,而不改变它的值。效果是改变指针运算的伸缩。
- 指针可以指向函数
函数名为指针。可以将指针赋值为函数,并且用指针来调用函数。
函数指针的值是该函数机器代码表示中第一条指令的地址。
10.1 内存布局
堆中:大变量在高地址,小变量在低地址,便于内存的回收与释放,减少内存碎片
10.2 缓冲区溢出 buffer overflow
C对于数组引用不进行任何边界检查,而且局部变量和状态信息(保存的寄存器值和返回地址等)都存放在栈中。对越界的数组元素的写操作会破坏存储在栈中的状态信息,当程序使用被破坏的状态,试图重新加载寄存器或执行ret指令时就会出现很严重的错误。
安全隐患
一种常见的状态破坏称为缓冲区溢出,通常在栈中分配某个字符数组来保存一个字符串,但是字符串的长度超出了为数组分配的空间。
缓冲区溢出的一个更加致命的使用就是让程序执行它本来不愿意执行的函数。这是一种最常见的通过计算机网络攻击系统安全的方法。通常,输入给程序一个字符串,这个字符串包含一些可执行代码的字节编码,称为攻击代码(exploit code),另外,还有一些字节会用一个指向攻击代码的指针覆盖返回地址。那么,执行ret指令的效果就是跳转到攻击代码。
在一种攻击形式中,攻击代码会使用系统调用启动一个shell程序,给攻击者提供一组操作系统函数。在另一种攻击形式中,攻击代码会执行一些未授权的任务,修复对栈的破坏,然后第二次执行ret指令,(表面上)正常返回到调用者。
防护
- 避免溢出漏洞
使用fgets代替gets: char *fgets(char *str, int n, FILE *stream)
一般用fgets(buf, sizeof(buf), stdin)
使用strncpy代替strcpy
在scanf函数中别用%s:使用fgets读入字符串,或用%ns代替%s,其中n是一个合适的整数
- 使用系统级的防护
①随机栈偏移(地址空间布局随机化技术的一部分):程序启动后,在栈中分配随机数量的空间,将移动整个程序使用的栈空间地址,每次程序执行,栈都重新定位,很难预测插入代码的起始地址。
②非可执行段:标记存储区为“只读”或“可写”,但不给予“执行”权限,将stack标记为不可执行。
- 编译器使用“栈金丝雀”(stack canaries) / 哨兵值(guard value)
在栈中buffer之后的位置放置特殊的值——金丝雀(canary),退出函数之前,检查是否被破坏。编译器默认开启。
相关文章:

《深入理解计算机系统(CSAPP)》第3章 程序的机器级表示 - 学习笔记
写在前面的话:此系列文章为笔者学习CSAPP时的个人笔记,分享出来与大家学习交流,目录大体与《深入理解计算机系统》书本一致。因是初次预习时写的笔记,在复习回看时发现部分内容存在一些小问题,因时间紧张来不及再次整理…...

【数据结构】第六周
目录 银行排队——队列 公共钥匙盒——队列 等值子串 KMP模式匹配 大整数相乘 最长公共子串 银行排队——队列 【问题描述】 我们大多都有在银行排队的经历,唉,那坑爹的排队啊!现在就让我们来算算我们这些客户平均需要等多久吧。 每天…...

6.4.6拓扑排序
用DAG(有向无环图)表示一个工程。顶点表示活动,有向边<Vi,Vj>表示活动Vi活动必须先与Vj活动进行。 所谓的拓扑排序:找到做事的先后顺序 以上根据拓扑排序的实现: 加入对有回路的图进行拓扑排序&#…...

Ae:常用内置抠像效果
Ae 中的抠像都是基于效果控件来实现的,最终生成动态遮罩来控制画面像素的透明度。 常用的内置抠像效果有:提取、线性颜色键、颜色差值键、内部/外部键等。 黑色或白色背景的抠像 对于白色或黑色背景的素材,可直接尝试图层混合模式。 或者&…...

[ 支付宝支付笔记]
目录 前言: 支付宝支付: 创建AlipayClient对象(注意,这里的appId、私钥、公钥等信息需要根据实际情况进行替换): 构造AlipayTradePagePayRequest对象,设置订单信息等参数: 调用AlipayClient对象的page…...

2023九坤投资暑期实习笔试复盘
5.22号笔试,5.24确认自己笔试挂。想想这也是自己第一次做量化私募基金的笔试,在此复盘一下。情况:北邮本硕。但开始准备暑期准备的比较晚,4月初才开始一边刷题一边投简历,所以手撕算法不太强,但运气和灵感好…...

深度学习的定义和未来发展趋势
深度学习的定义和未来发展趋势 什么是深度学习数学和编程的基础知识深度学习的应用领域深度学习的常见算法和模型训练深度学习模型深度学习的未来 🏘️🏘️个人简介:以山河作礼。 🎖️🎖️:Python领域新星创作者&#…...

如何更改 Linux 文件和目录权限?
在Linux系统中,文件和目录权限是安全性和访问控制的关键组成部分。正确设置文件和目录的权限可以确保只有授权的用户能够读取、写入或执行这些文件和目录。 本文将详细介绍如何在Linux系统中更改文件和目录的权限。 1. 文件和目录权限概述 在Linux系统中ÿ…...

Revit楼板问题:楼板连接处以及楼板开洞,一键开洞
在我们做楼梯时,楼梯与楼板处的连接处理不是那么符合实际,会出现一些问题,如下图,这样的连接会导致楼梯配筋时钢筋外露。 我们来学习如何调节楼板与楼板连接处的高度,选中楼梯,点击“编辑楼梯”在所需要更改…...

【AI领域+餐饮】| 论ChatGPT在餐饮行业的应用展望
💂作者简介: THUNDER王,一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读,同时任汉硕云(广东)科技有限公司ABAP开发顾问。在学习工作中,我通常使用偏后…...

【计算机视觉 | 目标检测】arxiv 计算机视觉关于目标检测的学术速递(5月29日论文合集)
文章目录 一、检测相关(12篇)1.1 Linear Object Detection in Document Images using Multiple Object Tracking1.2 Hybrid Energy Based Model in the Feature Space for Out-of-Distribution Detection1.3 BEV-IO: Enhancing Birds-Eye-View 3D Detection with Instance Occu…...

Altium Designer 相同电路多组复制布线
在进行设计开发的时候,总会遇到相同的电路,或者模块,这些电路可以使用相同的布局和走线。我们可以画好其中一部分,然后直接复制,就可以提高效率。下面记录我自己的实际操作过程,有一些地方遇到了问题&#…...

C++线程池介绍和C++代码实现
1、介绍 1.1 线程池应用场景 在进行创建线程任务时,如果需要频繁的创建线程、销毁线程,这样会极大地降低效率,因为创建线程也是需要时间的,一个完整的线程处理运行时间包括:线程的创建时间、线程运作时间、线程的销毁…...

【day 06】vue的组件
组件 组件就是把一个网页分割成独立的小的模块,然后通过把模块进行组合,构建成一个大型的应用 单文件组件 只有一个组件 html css js 都在这个文件内 非单文件组件 可有多个组件 全局注册 !! 得先注册子组件 再生成 vm实例对象 创建子组件 const …...

第3章 Class and Object
构造函数 Guaranteed initialization with the constructor使用构造函数保证初始化 • If a class has a constructor, the compiler automatically calls that constructor at the point an object is created, before client programmers can get their hands on the o…...

卫星定位北斗芯片AT6558一款高性能BDS/GNSS多模卫星导航接收机SOC单芯片
1 芯片简介 AT6558R是一款高性能BDS/GNSS多模卫星导航接收机SOC单芯片,片上集成射频前端, 数字基带处理器,32位的RISCCPU,电源管理功能。 芯片支持多种卫星导航系统,包括中国的北斗卫星导航系统BDS,美国的GPS,俄罗斯 的…...

提升您的 MQTT 云服务:深入探索 BYOC
引言 您是否希望将物联网基础设施提升到更高的水平?为了应对业务的不断扩展,您需要一个强大且安全的消息平台来支持它。 MQTT 协议凭借其轻量级、发布/订阅模型和可靠性,已经成为构建物联网平台的首选方案。但是,随着业务的增长…...

Zookeeper面试题总结
1、说说 Zookeeper 是什么? 有些软件你想做成集群或者分布式,你可以用 ZooKeeper 帮你来辅助实现。特点:ZooKeeper 的特点:维护、协调、管理、监控 最终一致性:客户端看到的数据最终是一致的。可靠性:服务…...

如何使用HTML、CSS和JavaScript来制作这两种类型的时钟
随着计算机技术的不断发展和普及,人们对于时间的精准度要求也越来越高。时钟作为我们日常生活必不可少的工具之一,也得到了越来越多的关注和研究。而在Web开发中,我们同样可以使用HTML、CSS和JavaScript的组合,制作出各式各样的时…...

Java中操作Xml使用备忘
List item 文章目录 Java中操作Xml使用备忘1. Hutool中XmlUtil的使用简介2. Hutool中XmlUtil快速读取Xml字符串某个节点值 [简单取值时,推荐使用]2-1 Hutool工具包Maven依赖和测试Xml字符串如下2-2 读取Xml中的节点<message>的值 3. Hutool中XmlUtil详细操作示…...

【Java|基础篇】内部类
文章目录 1.什么是内部类?2.实例内部类3.静态内部类4.局部内部类5.匿名内部类6.结语 1.什么是内部类? 内部类就是在一个类中再定义一个类,内部类也是封装的体现.它可以被声明为 public、protected、private 或默认访问控制符。内部类可以访问外部类的所有成员变量和方法&…...

七牛云图床设置
文章目录 七牛云图床设置下面是用picgo配置图床SSL证书申请https网站显示http图片解决方案 原文链接图床设置,免费SSL证书申请,https网站显示http链接的图片 七牛云图床设置 登录七牛云官网并进行个人注册,然后找到对象存储 点击空间管理&a…...

Android 12.0下拉状态栏录屏去掉弹窗直接录屏
1.概述 在12.0的系统rom开发中,在systemui的下拉状态栏中有个录屏的快捷按钮,可以通过点击录屏实现录屏功能,但是在录屏的时候发现需要先弹出 dialog,然后点击开始实现录屏,这有的麻烦,所以需要去掉弹窗直接开始录屏,就需要弹窗的相关代码来实现功能 2.下拉状态栏录屏…...

MySql基础学习(1)
MySql基础学习 一、数据库1.1 什么是数据库1.2 MySql的启动与停止1.3 MySql数据模型 二、SQL2.1 SQL通用语法2.2 SQL分类2.2.1 数据类型2.2.2 DDL使用方法2.2.3 、表操作-修改&删除DDL总结 2.3 DML2.3.1 DML添加数据2.3.2 DML---修改数据2.3.3 DML---删除数据DML总结 2.4 D…...

18- 弹幕系统设计
1、弹幕系统设计 场景分析:客户端针对某一视频创建了弹幕,发送后端进行处理,后端需要对所有正在观看该视频的用户推送该弹幕。 1.1、实现方式 使用短连接进行通信或使用长连接进行通信。 1.1.1、短连接实现方案 所有观看视频的客户端不断…...

字节软测划水四年,内容过于真实......
先简单交代一下吧,潇潇是某不知名211的本硕,18年毕业加入一个小厂,之后跳槽到了字节跳动,一直从事测试开发相关的工作。之前没有实习经历,算是四年半的工作经验吧。 这四年半之间他完成了一次晋升,换了一家…...

Mybatis介绍
1. Mybatis中#和$的区别? #相当于对数据 加上 双引号,$相当于直接显示数据 1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为orde…...

Docker理论基础
初识Docker 1.什么是Docker 微服务虽然具备各种各样的优势,但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中,依赖的组件非常多,不同组件之间部署时往往会产生一些冲突。 在数百上千台服务中重复部署,环境不一定一致&…...

MySQL数据库之存储引擎
一、存储引擎的概念 1.1 什么是存储引擎 MySQL中的数据用各种不下同的技术存储在文件中,每一种技术都使用不同的存储机制、索引技巧、锁定水平并最终提供不同的功能和能力,这些不同的技术以及配套的功能在MySQL中称为存储引擎。存储引擎是MySQL将数据存…...

中介效应分析全流程汇总
一、中介效应说明 中介效应主要研究自变量对因变量影响的过程中,自变量是否通过中介变量再对因变量产生影响,那什么情况表明中介效应存在呢?如果自变量对因变量影响过程中,中介变量在模型中有着桥梁般的作用,那说明中…...