整理复习汇编语言的知识点,以前在学习《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. Web 3.0 会是互联网的下一个时代吗?

    2000 年初,只读互联网 Web 1.0 被 Web 2.0 所取代.在 Web 2.0 时代,用户摆脱了只读的困扰,可以在平台上进行互动并创作内容.而 Web 3.0 的到来,除了加密货币和区块链 ...

  2. 面试官:请聊一聊String、StringBuilder、StringBuffer三者的区别

    面试官:"小伙子,在日常的写代码过程中,使用过String,StringBuilder和StringBuffer没?" 我:"用过的呀!" 面试官:" ...

  3. #1016:Prime Ring Problem(经典DFS)

    原题链接 题意:很容易理解,就是让你输出满足相邻的相加是素数的序列(注意不要重复) 思路就是深搜思想把每种情况遍历一次 代码实现: #include<iostream> #include& ...

  4. 【网络爬虫学习】Python 爬虫初步

    本系列基于 C语言中文网的 Python爬虫教程(从入门到精通)来进行学习的, 部分转载的文章内容仅作学习使用! 前言 网络爬虫又称网络蜘蛛.网络机器人,它是一种按照一定的规则自动浏览.检索网页信息的 ...

  5. 题解 [HDU 6745] Dec (简单DP)

    来源:2020 年百度之星·程序设计大赛 - 初赛一 错误想法带来错的代码, 为什么一个简单DP题能被我想成复杂的贪心啊?? 初始有 \(a,b\) 两个正整数,每次可以从中选一个大于 1 的数减 1 ...

  6. 详解 Serverless 架构的 6 大应用场景

    导读 Serverless 架构将成为未来云计算领域重要的技术架构,将会被更多的业务所采纳.进一步深究,Serverless 架构在什么场景下有优秀的表现,在什么场景下可能表现得并不是很理想呢?或者说 ...

  7. C#开源跨平台的多功能Steam工具箱&GitHub加速神器

    前言 作为一个程序员你是否会经常会遇到GitHub无法访问(如下无法访问图片),或者是访问和下载源码时十分缓慢就像乌龟爬行一般.今天分享一款C#开源的.跨平台的多功能Steam工具箱和GitHub加速 ...

  8. Webpack Vue瘦身,感受快到飞起的加载速度!

    症结 在利用webpack脚手架搭建vue项目后,往往最终打包的.js和.css文件过于庞大,造成首次加载的时候白屏时间过长,影响用户体验,下图为未经任何优化直接npm run build之后的情况: ...

  9. freeswitch号码变化方案

    概述 freeswitch是一款简单易用的开源音视频软交换平台. 在生产环境中,由于各个线路的号码规则并不统一,经常需要针对中继线路做号码变换的方案. 本文主要介绍fs中有哪些可选的号码变换方案. 环 ...

  10. 面向对象C++学习总结

    洛谷日记3 2023.5 面向对象C++ : 运算符重载 1.运算符重载 (1)n定义重载运算符和定义普通函数类似,只是该函数的名字是operator@,@表示要重载的运算符. MinInt oper ...