整理复习汇编语言的知识点,以前在学习《Intel汇编语言程序设计 - 第五版》时没有很认真的整理笔记,主要因为当时是以学习理解为目的没有整理的很详细,这次是我第三次阅读此书,每一次阅读都会有新的收获,这次复习,我想把书中的重点,再一次做一个归纳与总结(注:16位汇编部分跳过),并且继续尝试写一些有趣的案例,这些案例中所涉及的指令都是逆向中的重点,一些不重要的我就直接省略了,一来提高自己,二来分享知识,转载请加出处,敲代码备注挺难受的。

本次复习重点在于理解数组中常用的寻址方式以及标志位的测试命令,数组寻址包括了,直接寻址,间接寻址,立即数寻址,基址变址寻址,比例因子寻址,通过ESI内存寻址,通过ESP堆栈寻址,指针寻址。

再次强调:该笔记主要学习的是汇编语言,不是研究编译特性的,不会涉及到编译器的优化与代码还原。

数组取值操作符: 数组取值操作符是对数组操作之前必须要掌握的,以下命令主要实现对数组元素的统计,取偏移值等,后期数组寻址会用到.

	.386p
.model flat,stdcall
option casemap:none include windows.inc
include kernel32.inc
includelib kernel32.lib .data
WordVar1 WORD 1234h
DwordVar2 DWORD 12345678h ArrayBT BYTE 1,2,3,4,5,6,7,8,9,0h
ArrayDW DWORD 1000,2000,3000,4000,5000,6000,7000,8000,9000,0h
ArrayTP DWORD 30 DUP(?)
.code main PROC
; 使用 OFFSET 可返回数据标号的偏移地址,单位是字节.
; 偏移地址代表标号距DS数据段基址的距离.
xor eax,eax
mov eax,offset WordVar1
mov eax,offset DwordVar2 ; 使用 PTR 可指定默认取出参数的大小(DWORD/WORD/BYTE)
mov eax,dword ptr ds:[DwordVar2] ; eax = 12345678h
xor eax,eax
mov ax,word ptr ds:[DwordVar2] ; ax = 5678h
mov ax,word ptr ds:[DwordVar2 + 2] ; ax = 1234h ; 使用 LENGTHOF 可以计算数组元素的数量
xor eax,eax
mov eax,lengthof ArrayDW ; eax = 10
mov eax,lengthof ArrayBT ; eax = 10 ; 使用 TYPE 可返回按照字节计算的单个元素的大小.
xor eax,eax
mov eax,TYPE WordVar1 ; eax = 2
mov eax,TYPE DwordVar2 ; eax = 4
mov eax,TYPE ArrayDW ; eax = 4 ; 使用 SIZEOF 返回等于LENGTHOF(总元素数)和TYPE(每个元素占用字节)返回值的乘基.
xor eax,eax
mov eax,sizeof ArrayBT ; eax = 10
mov eax,sizeof ArrayTP ; eax = 120 invoke ExitProcess,0
main ENDP
END main

数组直接寻址: 在声明变量名称的后面加上偏移地址即可实现直接寻址,直接寻址中可以通过立即数寻址,也可以通过寄存器相加的方式寻址,如果遇到双字等还可以使用基址变址寻址,这些寻址都属于直接寻址.

	.386p
.model flat,stdcall
option casemap:none include windows.inc
include kernel32.inc
includelib kernel32.lib .data
ArrayB BYTE 10h,20h,30h,40h,50h
ArrayW WORD 100h,200h,300h,400h
ArrayDW DWORD 1h,2h,3h,4h,5h,6h,7h,8h,9h
.code
main PROC
; 针对字节的寻址操作
mov al,[ArrayB] ; al=10
mov al,[ArrayB+1] ; al=20
mov al,[ArrayB+2] ; al=30 ; 针对内存单元字存储操作
mov bx,[ArrayW] ; bx=100
mov bx,[ArrayW+2] ; bx=200
mov bx,[ArrayW+4] ; bx=300 ; 针对内存单元双字存储操作
mov eax,[ArrayDW] ; eax=00000001
mov eax,[ArrayDW+4] ; eax=00000002
mov eax,[ArrayDW+8] ; eax=00000003 ; 基址加偏移寻址: 通过循环eax的值进行寻址,每次eax递增2
mov esi,offset ArrayW
mov eax,0
mov ecx,lengthof ArrayW
s1:
mov dx,word ptr ds:[esi + eax]
add eax,2
loop s1 ; 基址变址寻址: 循环取出数组中的元素
mov esi,offset ArrayDW ; 数组基址
mov eax,0 ; 定义为元素下标
mov ecx,lengthof ArrayDW ; 循环次数
s2:
mov edi,dword ptr ds:[esi + eax * 4] ; 取出数值放入edi
inc eax ; 数组递增
loop s2 invoke ExitProcess,0
main ENDP
END main

数组间接寻址: 数组中没有固定的编号,处理此类数组唯一可行的方法是用寄存器作为指针并操作寄存器的值,这种方法称为间接寻址,间接寻址通常可通过ESI实现内存寻址,也可通过ESP实现对堆栈的寻址操作.

	.386p
.model flat,stdcall
option casemap:none include windows.inc
include kernel32.inc
includelib kernel32.lib .data
ArrayDW DWORD 1h,2h,3h,4h,5h,6h,7h,8h,9h
.code
main PROC
; 第一种: 通过使用ESI寄存器实现寻址.
mov esi,offset ArrayDW ; 取出数组基地址
mov ecx,lengthof ArrayDW ; 取出数组元素个数
s1:
mov eax,dword ptr ds:[esi] ; 间接寻址
add esi,4 ; 每次递增4
loop s1 ; 第二种: 通过ESP堆栈寄存器,实现寻址.
mov eax,100 ; eax=1
mov ebx,200 ; ebx=2
mov ecx,300 ; ecx=3
push eax ; push 1
push ebx ; push 2
push ecx ; push 3 mov edx,[esp + 8] ; EDX = [ESP+8] = 1
mov edx,[esp + 4] ; EDX = [ESP+4] = 2
mov edx,[esp] ; EDX = [ESP] = 3 ; 第三种(高级版): 通过ESP堆栈寄存器,实现寻址.
push ebp
mov ebp,esp ; 保存栈地址
lea eax,dword ptr ds:[ArrayDW] ; 获取到ArrayDW基地址
; -> 先将数据压栈
mov ecx,9 ; 循环9次
s2: push dword ptr ss:[eax] ; 将数据压入堆栈
add eax,4 ; 每次递增4字节
loop s2
; -> 在堆栈中取数据
mov eax,32 ; 此处是 4*9=36 36 - 4 = 32
mov ecx,9 ; 循环9次
s3: mov edx,dword ptr ss:[esp + eax] ; 寻找栈中元素
sub eax,4 ; 每次递减4字节
loop s3 add esp,36 ; 用完之后修正堆栈
pop ebp ; 恢复ebp invoke ExitProcess,0
main ENDP
END main

比例因子寻址: 通过使用比例因子,以下例子每个DWORD=4字节,且总元素下标=0-3,得出比例因子3* type arrayDW.

	.386p
.model flat,stdcall
option casemap:none include windows.inc
include kernel32.inc
includelib kernel32.lib .data
ArrayW WORD 1h,2h,3h,4h,5h
ArrayDW DWORD 1h,2h,3h,4h,5h,6h,7h,8h,9h TwoArray DWORD 10h,20h,30h,40h,50h
RowSize = ($ - TwoArray) ; 每行所占空间 20 字节
DWORD 60h,70h,80h,90h,0ah
DWORD 0bh,0ch,0dh,0eh,0fh
.code
main PROC ; 第一种比例因子寻址
mov esi,0 ; 初始化因子
mov ecx,9 ; 设置循环次数
s1:
mov eax,ArrayDW[esi * 4] ; 通过因子寻址,4 = DWORD
add esi,1 ; 递增因子
loop s1 ; 第二种比例因子寻址
mov esi,0
lea edi,word ptr ds:[ArrayW]
mov ecx,5
s2:
mov ax,word ptr ds:[edi + esi * type ArrayW]
inc esi
loop s2 ; 第三种二维数组寻址
row_index = 1
column_index = 2 mov ebx,offset TwoArray ; 数组首地址
add ebx,RowSize * row_index ; 控制寻址行
mov esi,column_index ; 控制行中第几个
mov eax, dword ptr ds:[ebx + esi * TYPE TwoArray] invoke ExitProcess,0
main ENDP
END main

通过比例因子可以模拟实现二维数组寻址操作,过程也很简单.

	.386p
.model flat,stdcall
option casemap:none include windows.inc
include kernel32.inc
includelib kernel32.lib .data
TwoArray DWORD 10h,20h,30h,40h,50h
RowSize = ($ - TwoArray) ; 每行所占空间 20 字节
DWORD 60h,70h,80h,90h,0ah
DWORD 0bh,0ch,0dh,0eh,0fh
.code
main PROC
lea esi,dword ptr ds:[TwoArray] ; 取基地址
mov eax,0 ; 控制外层循环变量
mov ecx,3 ; 外层循环次数
s1:
push ecx ; 保存外循环次数
push eax mov ecx,5 ; 内层循环数
s2: add eax,4 ; 每次递增4
mov edx,dword ptr ds:[esi + eax] ; 定位到内层循环元素
loop s2 pop eax
pop ecx
add eax,20 ; 控制外层数组
loop s1 invoke ExitProcess,0
main ENDP
END main

通过比例因子实现对数组求和操作,代码如下:

	.386p
.model flat,stdcall
option casemap:none include windows.inc
include kernel32.inc
includelib kernel32.lib .data
ArrayA DWORD 10h,20h,30h,40h,50h
ArrayB DWORD 10h,20h,30h,40h,50h
NewArray DWORD 5 dup(0)
.code
main PROC
; 循环让数组中的每一个数加10后回写
mov ebx,0
mov ecx,5
s1:
mov eax,dword ptr ds:[ArrayA + ebx * 4]
add eax,10
mov dword ptr ds:[ArrayA + ebx * 4],eax
inc ebx
loop s1 ; 循环让数组A与数组B相加后赋值到数组NewArray
mov ebx,0
mov ecx,5
s2:
mov esi,dword ptr ds:[ArrayA + ebx]
add esi,dword ptr ds:[ArrayB + ebx]
mov dword ptr ds:[NewArray + ebx],esi
add ebx,4
loop s2 invoke ExitProcess,0
main ENDP
END main

数组指针寻址: 变量地址的变量称为指针变量(pointer variable),Intel处理器使用两种基本类型的指针,即near(近指针)和far(远指针),保护模式下使用Near指针,所以它被存储在双字变量中.

	.386p
.model flat,stdcall
option casemap:none include windows.inc
include kernel32.inc
includelib kernel32.lib .data
ArrayA WORD 1h,2h,3h,4h,5h
ArrayB DWORD 1h,2h,3h,4h,5h PtrA DWORD offset ArrayA ; 指针 PtrA --> ArrayA
PtrB DWORD offset ArrayB ; 指针 PTRB --> ArrayB
.code
main PROC mov ebx,0 ; 寻址因子
mov ecx,5 ; 循环次数
s1:
mov esi,dword ptr ds:[PtrA] ; 将指针指向PtrA
mov ax,word ptr ds:[esi + ebx * 2] ; 每次递增2字节 mov esi,dword ptr ds:[PtrB] ; 将指针指向PtrB
mov eax,dword ptr cs:[esi + ebx * 4] ; 每次递增4字节
inc esi ; 基地址递增
inc ebx ; 因子递增
loop s1 invoke ExitProcess,0
main ENDP
END main

常见标志位测试: 标志寄存器又称程序状态寄存器,其主要用于存放条件码标志,控制标志和系统标志的寄存器,标志寄存器中存放的有条件标志,也有控制标志,这些标志则会影响跳转的实现,逆向中常见的标志位有如下几种.

	.386p
.model flat,stdcall
option casemap:none include windows.inc
include kernel32.inc
includelib kernel32.lib .code
main PROC
; CF 进位标志位: 当执行一个加法(或减法)运算,使最高位产生进位(或借位)时,CF为1;否则为0
mov ax,0ffffh
add ax,1 ; cf = 1 af = 1 ; PF 奇偶标志位: 当运算结果中,所有bit位(例:1001010)中1的个数为偶数时,则PF=1;为基数PF=0
mov eax,00000000b
add eax,00000111b ; pf = 0 mov eax,00000000b
add eax,00000011b ; pf = 1 ; ZF 零标志位: 若当前的运算结果为零,则ZF=1; 否则ZF=0
mov eax,2
sub eax,2 ; zf = 1 cf = 0 af = 0 ; SF 符号标志位: 若运算结果为负数,则SF=1;若为非负数则SF=0
mov eax,3e8h
sub eax,3e9h ; sf = 1 cf = 1 af = 1 zf = 0 ; DF 方向标志位: 当DF=0时为正向传送数据(cld),否则为逆向传送数据(std)
cld
mov eax,1 ; df = 0
std
mov eax,1 ; df = 1 ; OF 溢出标志位: 记录是否产生了溢出,当补码运算有溢出时OF=1;否则OF=0
mov al,64h
add al,64h ; of = 1 cf = 0 pf = 0 af = 0 invoke ExitProcess,0
main ENDP
END main

TEST 位与指令: 该指令在对操作数之间执行隐含与运算操作,并设置相应的标志位,与AND指令唯一的不同在于,该指令只会设置相应的标志,并不会替换目的操作数中的数值,常用于测试某些位是否被设置.

TEST指令可以同时检测设置多个标志位的值,该指令执行时总是清除溢出标志和进位标志,它修改符号标志,基偶标志,零标志的方式与AND指令相同.

	.386p
.model flat,stdcall
option casemap:none include windows.inc
include kernel32.inc
includelib kernel32.lib .code
main PROC
mov al,00001111b
test al,2 ; zf=0 pf=0 mov al,00100101b
test al,00001001b ; zf=0 pf=0 mov al,00100100b
test al,00001001b ; zf=1 pf=1 mov eax,0100h
test eax,eax ; zf=0 mov eax,0
test eax,eax ; zf=0 or al,80h ; 设置符号标志 zf=0 pf=0 sf=1
and al,7fh ; 清除符号标志 zf=1 pf=1 sf=0 mov al,0
or al,1 ; 清除符号标志 zf=0 pf=0 stc ; 设置进位标志 cf = 1
clc ; 清除进位标志 cf = 0 mov al,07fh ; AL = +127
inc al ; 设置溢出标志 AL = 80h (-128) of=1 af=1 sf=1
or eax,0 ; 清除溢出标志 invoke ExitProcess,0
main ENDP
END main

CMP 比较指令: 该指令作用是在源操作数和目的操作数中间执行隐含的减法运算,两个操作数都不会被修改,仅会影响标志位的变化,CMP指令是高级语言实现程序逻辑的关键,也是汇编中非常重要的指令常与跳转指令合用.

	.386p
.model flat,stdcall
option casemap:none include windows.inc
include kernel32.inc
includelib kernel32.lib .code
main PROC
; 比较5和10
mov ax,5
cmp ax,10 ; 5-10 > zf=0 cf=1 pf=0 af=1 sf=1 ; 比较两个相同数
mov ax,1000
mov cx,1000
cmp cx,ax ; 1000-1000 > zf=1 cf=0 pf=1 sf=0 ; 比较100和0
mov ax,100
cmp ax,0 ; 100-0 > zf=0 cf=0 pf=0 ; 比较100和50
mov eax,100
mov ebx,50
cmp eax,ebx ; 100-50 > zf=0 cf=0 pf=0 ; 比较-100和50
mov eax,-100
mov ebx,50
cmp eax,ebx ; -100-50 > sf=1 pf=1 ; 比较-100和-50
mov eax,-100
mov ebx,-50
cmp eax,ebx ; -100--50 > cf=1 af=1 pf=0 invoke ExitProcess,0
main ENDP
END main

标志跳转指令: 跳转指令分为多种,第一种常见的跳转指令就是基于特定CPU的标志寄存器来实现的跳转形式.

	.386p
.model flat,stdcall
option casemap:none include windows.inc
include kernel32.inc
includelib kernel32.lib .code
main PROC
; JZ/JE 当ZF置1时 也就是结果为零则跳转 (leftOp - rightOp = 0)
mov eax,1
sub eax,1 ; zf=1 pf=1
je jump mov eax,1
mov ebx,1
cmp eax,ebx ; zf=1
jz jump ; JNZ/JNE 当ZF置0时 也就是结果不为零则跳转 (leftOp - rightOp != 0)
mov eax,2
sub eax,1
jnz jump ; zf=0 pf=0 mov eax,2
cmp eax,1
jne jump ; zf=0 ; JC/JNC 当 CF=1/0 设置进位标志则跳/未设置进位标志则跳
mov al,0
cmp al,1
jc jump
jnc jump ; JO/JNO 当 OF=1/0 设置溢出标志则跳/未设置溢出标志则跳
mov al,0ffh
add al,1
jo jump ; JS/JNS 当 SF=1/0 设置符号标志则跳/未设置符号标志则跳
mov eax,1
cmp eax,1
js jump ; cf=0 af=0 ; JP/JNP PF=1/0 设置奇偶标志则跳(偶)/未设置奇偶标志则跳(基)
mov al,00100100b
cmp al,0
jp jump ; zp=0
jump:
xor eax,eax
xor ebx,ebx invoke ExitProcess,0
main ENDP
END main

比较跳转标志: 通过使用cmp eax,ebx比较等式两边的值,影响相应的标志寄存器中的值,从而决定是否要跳转,常用的如下:

	.386p
.model flat,stdcall
option casemap:none include windows.inc
include kernel32.inc
includelib kernel32.lib .code
main PROC
; JA(无符号)/JG(有符号) 跳转标志: (left > right) 大于则跳转
mov eax,100
mov ebx,200
cmp ebx,eax ; 无符号 ebx > eax
ja jump ; zf=0 pf=0 mov eax,20
mov ebx,-100
cmp eax,ebx ; 有符号 eax > ebx
jg jump ; zf=0 cf=1 pf=1 af=1 ; JAE(无符号)/JGE(有符号) 跳转标志: (left >= right) 大于或等于则跳转
mov eax,50
mov ebx,20
cmp eax,ebx ; 无符号 eax >= ebx
jae jump ; jae 被替换成了jnb 小于则跳 (eax<ebx) mov eax,50
mov ebx,-20
cmp eax,ebx ; 有符号 eax >= ebx
jge jump ; zf=0 af=1 pf=0 sf ; JB(无符号)/JL(有符号) 跳转标志:(left < right) 小于则跳转
mov eax,10
mov ebx,20
cmp eax,ebx ; 无符号 eax < ebx
jb jump ; cf=0 af=0 pf=1 mov eax,-10
mov ebx,20
cmp eax,ebx ; 有符号 eax < ebx
jl jump ; JBE(无符号)/JLE(有符号) 跳转标志:(left <= right) 小于或等于则跳转
mov eax,20
mov ebx,20
cmp eax,ebx ; 无符号 eax <= ebx
jbe jump ; zf=1 mov eax,-20
mov ebx,10
cmp eax,ebx ; 无符号 eax,ebx
jle jump ; sf=1 ; JNB(不小于则跳 同JAE)/JNA(不大于则跳 同JBE) 跳转标志:(lef !>< right) 无符号
mov eax,10
mov ebx,5
cmp eax,ebx ; eax !< ebx
jnb jump mov eax,5
mov ebx,10
cmp eax,ebx ; eax !> ebx
jbe jump ; JNB(不小于则跳 同JAE)/JNA(不大于则跳 同JBE) 跳转标志:(lef !>< right) 无符号
mov eax,10
mov ebx,5
cmp eax,ebx ; eax !< ebx
jnb jump ; zf=0 cf=0 mov eax,5
mov ebx,10
cmp eax,ebx ; eax !> ebx
jbe jump ; cf=1 af=1 zf=0 ; JNL(不小于则跳 同JGE)/JNG(不大于则跳 同JLE) 跳转标志:(lef !>< right) 有符号
mov eax,10
mov ebx,-5
cmp eax,ebx ; eax !< ebx
jnl jump ; sf=0 cf=1 pf=1 af=1 zf=0 mov eax,-10
mov ebx,5
cmp eax,ebx ; eax !> ebx
jng jump ; sf=1 jump:
xor eax,eax
xor ebx,ebx invoke ExitProcess,0
main ENDP
END main

BT/BSF/BSR 位测试指令: 首先BT系列命令主要用于对特定寄存器进行测试,清除,设置或求反等操作,它会影响CF标志位,而BSF/BSR命令则是对特定位中的值进行正反向扫描操作,它会影响ZF标志位.

	.386p
.model flat,stdcall
option casemap:none include windows.inc
include kernel32.inc
includelib kernel32.lib .code
main PROC
; bt 普通的位测试命令
xor edx,edx
mov dx,10000001b
bt dx,7 ; 把DX第7位送入CF = 1
bt dx,6 ; 把DX第六位送入CF = 0 ; bts 位测试并置位
mov dx,10000001b
bts dx,6 ; cf = 0
bts dx,7 ; cf = 1 ; btr 位测试并复位.在执行BT同时,把操作数的指定位置为0
mov dx,10000001b
btr dx,7
btr dx,6 ; cf = 0 ;btc 位测试并取反.在执行BT同时,把操作数的指定位取反
mov dx,10000001b
btc dx,0 ; cf = 1
btc dx,0 ; cf = 0 ; BSF 执行位扫描 由低->高位 | BSR 由高 -> 到低
xor edx,edx
mov dx, 0000111100001100b
bsf cx,dx ; 正向扫描,将扫描到1的位置放入CX
bsr cx,dx ; 反向扫描 zf=0 pf=0 xor ecx,ecx
mov cx,0
mov dx,0
bsf cx,dx
lahf invoke ExitProcess,0
main ENDP
END main

Win32汇编:数组与标志位测试总结的更多相关文章

  1. AU3中BitAnd与Win32汇编中的&按位进行与操作的本质思考

    心越静,思考的越透彻.不要着急,宇宙有求必应!我可能是最笨的才会写出来进行思考,写出来至少自己在碰到这些本质上的问题不会再度卡壳.本着"没有交流的思考不是完整的思考"的原则,我将这 ...

  2. 学 Win32 汇编[20]: 洞察标志寄存器

    15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 NT IOPL OF DF IF TF SF ZF AF PF CF 未使用 嵌套标志 I/O权限标志占2位 溢出标志 方向 ...

  3. 计算机二级-C语言-对标志位的巧妙使用。对二维数组数据进行处理。对文件进行数据输入。

    //函数fun的功能是:计算形参x所指数组中平均值(规定所有数均为正数),将所指数组中大于平均值的数据移至数组的前部,小于等于的移至后部,平均值作为返回值,在主函数中输出平均值和后移的数据. //重难 ...

  4. 汇编 OD 标志位 置位相关指令

    知识点: l 标志位 置位相关指令   l 标志寄存器PSW 标志寄存器PSW(程序状态字寄存器PSW)    标志寄存器PSW是一个16为的寄存器.它反映了CPU运算的状态特征并且存放某些控制标志. ...

  5. Win32汇编学习(10):对话框(1)

    现在我们开始学习一些有关GUI编程的有趣的部分:以对话框为主要界面的应用程序. 理论: 如果您仔细关注过前一个程序就会发现:您无法按TAB键从一个子窗口控件跳到另一个子窗口控件,要想转移的话只有 用鼠 ...

  6. Win32汇编常用算数指令

    汇编语言(assembly language)是一种用于电子计算机.微处理器.微控制器或其他可编程器件的低级语言,亦称为符号语言.在汇编语言中,用助记符(Mnemonics)代替机器指令的操作码,用地 ...

  7. Win32汇编环境配置

    放假了,发现自己知识面窄,趁有时间就打算折腾下Win32汇编.其实在学校也上过汇编课,是基于dos的.那时老师不务正业,老跟我们讲政治经济文化,唯独不怎么讲课;再加上自己的问题,导致了dos汇编学得好 ...

  8. 内核参数优化之2-1 tcp/ip 标志位报文解析

    以下内容纯属虚构,切勿轻易相信! 众所周知,tcp/ip三次握手和四次挥手,均由syn/ack/fin三个标志位报文决定,但是这三个标志位报文,并不是说在构建连接的时候只发送一次的,因为协议不知道网络 ...

  9. Win32汇编学习(11):对话框(2)

    我们将进一步学习对话框,探讨如何把对话框当成输入设备.如果您看了前一篇文章,那就会发现这次的例子只有少量的改动,就是把我们的对话框窗口附属到主窗口上.另外,我们还要学习通用对话框的用法. 理论: 把对 ...

  10. Win32汇编学习(5):绘制文本2

    这次我们将学习有关文本的诸多属性如字体和颜色等. 理论: Windows 的颜色系统是用RGB值来表示的,R 代表红色,G 代表绿色,B 代表蓝色.如果您想指定一种颜色就必须给该颜色赋相关的 RGB ...

随机推荐

  1. Python pickle 二进制序列化和反序列化 - 数据持久化

    模块 pickle 实现了对一个 Python 对象结构的二进制序列化和反序列化. "pickling" 是将 Python 对象及其所拥有的层次结构转化为一个字节流的过程,而 & ...

  2. django的简单学习

    前言 以下项目实现基于一个投票系统 安装django 命令行安装 pip install django pycharm安装 pycharm的setting里找到这个,点击+号,搜索django 点击I ...

  3. 5分钟教会你如何在生产环境debug代码

    前言 有时出现的线上bug在测试环境死活都不能复现,靠review代码猜测bug出现的原因,然后盲改代码直接在线上测试明显不靠谱.这时我们就需要在生产环境中debug代码,快速找到bug的原因,然后将 ...

  4. python global函数的使用

    1.在全局变量与局部变量均存在时自定义的函数优先使用局部变量,自定义函数并不能改变全局变量的值. 查看运行结果:  2.在没有局部变量时,使用全局变量,且函数内部不能改变全局变量的值  查看运行结果: ...

  5. java基础(3)--pulic class与class的区别

    1.一个类前面的public是可有可无的2.如果一个类使用 public 修饰,则文件名必须与类名一致3.如果一个类前面没有使用public修饰,则文件名可以与类名不一致.当编译成功后会生成对应类名的 ...

  6. 如何实现 Excel 表格转置(行列互换)

    直接上经验贴: https://baijiahao.baidu.com/s?id=1690475581736550777&wfr=spider&for=pc 大概就是 先复制粘贴,在粘 ...

  7. zookeeper源码(03)启动流程

    本文将从启动类开始详细分析zookeeper的启动流程: 加载配置的过程 集群启动过程 单机版启动过程 启动类 org.apache.zookeeper.server.quorum.QuorumPee ...

  8. Nacos源码 (5) Grpc服务端和客户端

    Nacos 2.x在服务端与客户端直接增加了GRPC通信方式,本文通过2.0.2版本源码,简单分析GRPC通信方式: 服务器启动 客户端连接 客户端心跳 服务器监控检查 服务器 proto文件 api ...

  9. Verilog Review

    Agenda 目的 Verilog概述 Verilog建模 模块 模块组成 书写建议 时延 Verilog基本语法 标识符 可读性 注释 空格 数据类型 操作数 运算符 条件语句 循环语句 函数 Ve ...

  10. 17-三态门(TSL)

    三态门(TSL) 普通的逻辑电路只有两个状态,还有一个高阻态. EN是高电平1 A,B,EN之间的关系是与的关系,当EN为1得时候,EN就不起作用了,输入由A,B决定.EN端为高电平,所以二极管D2截 ...