程序的机器级表示part3——算术和逻辑操作
目录
1.加载有效地址
2. 整数运算指令
2.1 INC 和 DEC
2.2 NEG
2.3 ADD、SUB 和 IMUL
3. 布尔指令
3.1 AND
3.2 OR
3.3 XOR
3.4 NOT
4. 移位操作
4.1 算术左移和逻辑左移
4.2 算术右移和逻辑右移
5. 特殊的算术操作
1.加载有效地址
| 指令 | 效果 | 描述 |
| leaq S, D | D ← &S | 加载有效地址 |
加载有效地址( load effective address )指令leaq是movq指令的变形,在64位系统下地址长度为64位,因此lea指令的大小后缀为q,没有其他变种,其目标操作数必须是一个寄存器
leaq指令非常特别,它的一般格式是 leaq (寄存器) 寄存器,看上去像是从内存中读取数据到寄存器,实际上leaq从不发生内存引用,也就是说leaq指令不访问内存,以下面的程序来说明
int main()
{int x = 10;int *ptr = &x;return 0;
}00000000004004ed <main>:4004ed: 55 push %rbp4004ee: 48 89 e5 mov %rsp,%rbp4004f1: c7 45 f4 0a 00 00 00 movl $0xa,-0xc(%rbp)4004f8: 48 8d 45 f4 lea -0xc(%rbp),%rax // 取a的地址放进%rax4004fc: 48 89 45 f8 mov %rax,-0x8(%rbp)400500: b8 00 00 00 00 mov $0x0,%eax400505: 5d pop %rbp400506: c3 retq 400507: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)40050e: 00 00
4004f8: 48 8d 45 f4 lea -0xc(%rbp),%rax
这条指令在mov指令中表示:以%rbp内存放的值作为基地址,加上偏移量0xc作为地址,再取这个地址处的数据,并将数据传送到寄存器%rax内
但在leaq指令则表示:以%rbp内存放的值作为基地址,加上偏移量0xc作为地址,将这个地址传送到寄存器内,也就是 &x 这一行为
%rbp是帧寄存器,保存着main函数栈帧的栈顶位置
假设%rbp的值是10000,地址1000c处保存的值是10
- movq指令将10传送到寄存器%rax
- leaq指令将1000c传送到寄存器%rax
leaq指令完成简单的基地址和偏移量的相加,实际上,leaq指令不光能完成地址的相加,也常用于普通的算术操作,比如下面一条指令
leaq 7(%rdx, %rdx, 4), %rax
假设寄存器%rdx的值为x,这条指令的意思是将 %rax的值设置成 x + 4x +7 ,参考linux下的寻址模式的计算,比如下面的代码
long scale(long x, long y, long z)
{long t = x + 4 * y + 12 * z;return t;
}/*long scale(long x, long y, long z)x in %rdi, y in %rsi, z in %rdx
*/
scale:leaq (%rdi,%rsi,4), %rax x + 4*yleaq (%rdx,%rdx,2), %rdx z + 2*z = 3*zleaq (%rax,%rdx,4), %rax (x+4*y) + 4*(3*z) = x + 4*y + 12*zret
因此,leaq指令也能完成加法和有限的乘法计算,需要注意的一点是,寻址模式中的比例因子只能是1,2,4,8,说明leaq指令完成乘法时,也只能与1,2,4,8相乘,上面代码中,第二行不能使用 leaq(%rax, %rdx, 12) 一步完成计算,而是要分成两步也正是因为这个原因
2. 整数运算指令
| 指令 | 效果 | 描述 |
| INC D | D ← D + 1 | 加1 |
| DEC D | D ← D - 1 | 减1 |
| NEG D | D ← - D | 取负 |
| NOT D | D ← ~ D | 取补 |
| ADD S, D | D ← D + S | 加 |
| SUB S, D | D ← D - S | 减 |
| IMUL S, D | D ← D * S | 乘 |
这些整数操作随着操作数大小的不同在使用时要加上操作数大小描述符,因而有四种不同的指令
前四条指令inc,dec,neg 和 not的操作数都只有一个,即是源又是目的,因此称为一元操作,这个操作数可以是一个寄存器,也可以是一个内存位置
后三条指令add,sub,imul 的操作数有两个,其中第二个操作数即作为源使用,又作为目的使用,因此称为二元操作
2.1 INC 和 DEC
INC(Increment)指令从操作数中加1,DEC(Decrement)指令从操作数中减1,二者均不影响CF
指令格式
- inc reg/mem
- dec reg/mem
使用下面的代码查看inc和dec指令的功能
#include <stdio.h>int main() {int x = 10;// printf("The value of x before the increment: %d\n", x); 10__asm__ ( "inc %0\n" : "=r" (x) : "0" (x) ); // printf("The value of x after the increment: %d\n", x); 11// printf("The value of x before the increment: %d\n", x); 11__asm__ ( "dec %0\n" : "=r" (x) : "0" (x) );// printf("The value of x after the increment: %d\n", x); 10return 0;
}
00000000004004ed <main>:4004ed: 55 push %rbp4004ee: 48 89 e5 mov %rsp,%rbp4004f1: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)4004f8: 8b 45 fc mov -0x4(%rbp),%eax4004fb: ff c0 inc %eax // 把%eax中的值加14004fd: 89 45 fc mov %eax,-0x4(%rbp)400500: 8b 45 fc mov -0x4(%rbp),%eax400503: ff c8 dec %eax // 把%eax中的值减1400505: 89 45 fc mov %eax,-0x4(%rbp)400508: b8 00 00 00 00 mov $0x0,%eax40050d: 5d pop %rbp40050e: c3 retq 40050f: 90 nop
2.2 NEG
NEG(negative):将数字转换为对应的二进制补码, 从而求得其相反数,影响的标志位有
进位标志CF、零标志ZF、符号标志SF、溢出标志OF、辅助进位标志AF和奇偶标志PF(结果低8位中,数值1 的个数是否为偶数)。
指令格式
- neg reg
- neg mem
使用下面的代码查看neg指令的功能
int main()
{int i = 10;i = -i;i = ~i;return 0;
}
00000000004004ed <main>:4004ed: 55 push %rbp4004ee: 48 89 e5 mov %rsp,%rbp4004f1: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)4004f8: f7 5d fc negl -0x4(%rbp) // i = -i;4004fb: b8 00 00 00 00 mov $0x0,%eax400500: 5d pop %rbp400501: c3 retq 400502: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)400509: 00 00 00 40050c: 0f 1f 40 00 nopl 0x0(%rax)
2.3 ADD、SUB 和 IMUL
ADD(addition):指令将同尺寸的源操作数和目的操作数相加
SUB(subtraction):指令将同尺寸的源操作数和目的操作数相减
IMUL(multiplication):指令将同尺寸的源操作数和目的操作数相乘
指令格式
- add 源操作数, 目的操作数
- sub 源操作数, 目的操作数
- imul 源操作数, 目的操作数
指令的源操作数可以是:立即数,寄存器,内存位置
指令的目的操作数可以是:寄存器,内存位置
使用下面的代码查看add,sub,和 imul 指令的功能
int main()
{int a = 10;int b = a + 10;int c = b - 15;a = a * b;
}00000000004004ed <main>:4004ed: 55 push %rbp4004ee: 48 89 e5 mov %rsp,%rbp4004f1: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) // int a = 10;4004f8: 8b 45 fc mov -0x4(%rbp),%eax4004fb: 83 c0 0a add $0xa,%eax // int b = a + 10;4004fe: 89 45 f8 mov %eax,-0x8(%rbp)400501: 8b 45 f8 mov -0x8(%rbp),%eax400504: 83 e8 0f sub $0xf,%eax // int c = b - 15;400507: 89 45 f4 mov %eax,-0xc(%rbp)40050a: 8b 45 fc mov -0x4(%rbp),%eax40050d: 0f af 45 f8 imul -0x8(%rbp),%eax // a = a * b;400511: 89 45 fc mov %eax,-0x4(%rbp)400514: 5d pop %rbp400515: c3 retq 400516: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)40051d: 00 00 00
3. 布尔指令
C语言里存在位操作符
分别对应下面的指令
| 指令 | 效果 | 描述 |
| AND S, D | D ← D & S | 与 |
| OR S, D | D ← D | 1 | 或 |
| XOR S, D | D ← D ^ S | 异或 |
| NOT D | D ← ~ D | 取补 |
3.1 AND
AND 指令在每对操作数的对应数据位之间执行布尔位“与”操作,并将结果存放在目的操作数中
指令格式
- AND reg/mem/imm, reg/mem
AND指令总是使得CF=0、OF=0,并依据目的操作数的值修改SF、ZF和PF的值
参考如下代码
int main()
{int x = 10; // 00000000 00000000 00000000 00001010int y = x & 8; // 00000000 00000000 00000000 00001000return 0;
}00000000004004ed <main>:4004ed: 55 push %rbp4004ee: 48 89 e5 mov %rsp,%rbp4004f1: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) // int x = 10;4004f8: 8b 45 fc mov -0x4(%rbp),%eax4004fb: 83 e0 08 and $0x8,%eax // int y = x & 8;4004fe: 89 45 f8 mov %eax,-0x8(%rbp)400501: b8 00 00 00 00 mov $0x0,%eax400506: 5d pop %rbp400507: c3 retq 400508: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)40050f: 00
3.2 OR
OR 指令在每对操作数的对应数据位之间执行布尔位“或” 操作,并将结果存放在目的操作数中
指令格式
- OR reg/mem/imm, reg/mem
OR指令总是使得CF=0、OF=0,依据目的操作数的值修改SF、ZF和PF的值
参考如下代码
int main()
{int x = 10; // 00000000 00000000 00000000 00001010int y = x | 8; // 00000000 00000000 00000000 00001000return 0;
}00000000004004ed <main>:4004ed: 55 push %rbp4004ee: 48 89 e5 mov %rsp,%rbp4004f1: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) // int x = 10;4004f8: 8b 45 fc mov -0x4(%rbp),%eax4004fb: 83 c8 08 or $0x8,%eax // int y = x | 84004fe: 89 45 f8 mov %eax,-0x8(%rbp)400501: b8 00 00 00 00 mov $0x0,%eax400506: 5d pop %rbp400507: c3 retq 400508: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)40050f: 00
3.3 XOR
XOR 指令在每对操作数的对应数据位之间执行布尔位“异或” 操作,并将结果存放在目的操作数中
指令格式
- XOR reg/mem/imm, reg/mem
OR指令总是使得CF=0、OF=0,依据目的操作数的值修改SF、ZF和PF的值
参考如下代码
int main()
{int x = 10; // 00000000 00000000 00000000 00001010int y = x ^ 8; // 00000000 00000000 00000000 00001000return 0;
}00000000004004ed <main>:4004ed: 55 push %rbp4004ee: 48 89 e5 mov %rsp,%rbp4004f1: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) // int x = 10;4004f8: 8b 45 fc mov -0x4(%rbp),%eax4004fb: 83 f0 08 xor $0x8,%eax // int y = x ^ 8;4004fe: 89 45 f8 mov %eax,-0x8(%rbp)400501: b8 00 00 00 00 mov $0x0,%eax400506: 5d pop %rbp400507: c3 retq 400508: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)40050f: 00
3.4 NOT
NOT 指令将一个操作数的所有数据位取反
指令格式
- NOT reg/mem
NOT 指令不修改任何状态标志
参考如下代码
int main()
{int x = 10; // 00000000 00000000 00000000 00001010int y = ~x; // 11111111 11111111 11111111 11110101return 0;
}00000000004004ed <main>:4004ed: 55 push %rbp4004ee: 48 89 e5 mov %rsp,%rbp4004f1: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) // int x = 10;4004f8: 8b 45 fc mov -0x4(%rbp),%eax4004fb: f7 d0 not %eax // ~x;4004fd: 89 45 f8 mov %eax,-0x8(%rbp) // int y = ~x;400500: b8 00 00 00 00 mov $0x0,%eax400505: 5d pop %rbp400506: c3 retq 400507: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)40050e: 00 00
4. 移位操作
C语言中移位操作符分为左移操作符(<<)和右移操作符(>>),而移位操作又分左移和右移
| 指令 | 效果 | 描述 |
| SAL k, D | D ← D << k | 算术左移 |
| SHL k, D | D ← D << k | 逻辑左移 (等同SAL) |
| SAR k, D | D ← D >> k | 算数右移 |
| SHL k, D | D ← D >> k | 逻辑右移 |
移位操作
- 第一个操作数是移位量k,也就是二进制位移动的位数
- 第二个操作数是要移位的数
注意:移位量可以是一个立即数,或者放在单字节寄存器%cl中(规定了只能放在这里)
%cl长8位,可表示0~255,因此移位量的最大可以达到255位,但是显然没有这么长的数据类型,因此实际上移位操作是根据要移动的数的位数来决定取%cl的哪些值的,
x86-64中,移位操作对w位长的数据值进行操作,移位量是由%cl寄存器的低m位决定的,这里2的m次方等于w,高位会被忽略
比如此时%cl内是0xFF
| %cl | 1111 1111 |
对于不同的数据类型
- char类型的数据,长8位,取%cl中的低三位 111,因此会移动7位
- short类型的数据,长16位,取%cl中低四位 1111,因此会移动15位
- int类型的数据,长32位,取%cl中低五位 11111,因此会移动31位
4.1 算术左移和逻辑左移
SAL(Arithmetic Left Shift):对目的操作数执行逻辑左移操作,低位填0 ,移出的最高位送CF
SHL(Logic Left Shift):与SAL指令等价
指令格式
- sal imm8/CL, reg/mem
- shl imm8/CL, reg/mem

参考如下代码
int main()
{int x = 10; // 00000000 00000000 00000000 00001010int y = x << 2; // 00000000 00000000 00000000 00101000return 0;
}00000000004004ed <main>:4004ed: 55 push %rbp4004ee: 48 89 e5 mov %rsp,%rbp4004f1: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) // int x = 10;4004f8: 8b 45 fc mov -0x4(%rbp),%eax4004fb: c1 e0 02 shl $0x2,%eax // x << 24004fe: 89 45 f8 mov %eax,-0x8(%rbp) // int y = x << 2;400501: b8 00 00 00 00 mov $0x0,%eax400506: 5d pop %rbp400507: c3 retq 400508: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)40050f: 00
4.2 算术右移和逻辑右移
SHR(Logic Shift Right ):对目的操作数执行逻辑右移操作,移出的数据位以0 填充,最低位被送到CF中
指令格式
- shr imm8/CL, reg/mem

SAL(Arithmetic Right Shift):用最高位填充空出的位,最低位拷贝至CF
指令格式
- sar imm8/CL, reg/mem

参考如下代码(这里算术右移最特殊,只演示算术右移)
int main()
{int x1 = 10; // 00000000 00000000 00000000 00001010int y1 = x1 >> 2; // 00000000 00000000 00000000 00000010int x2 = -10; // 11111111 11111111 11111111 11110110int y2 = x2 >> 2; // 11111111 11111111 11111111 11111101return 0;
}00000000004004ed <main>:4004ed: 55 push %rbp4004ee: 48 89 e5 mov %rsp,%rbp4004f1: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)4004f8: 8b 45 fc mov -0x4(%rbp),%eax4004fb: c1 f8 02 sar $0x2,%eax // 算术右移,以0填充4004fe: 89 45 f8 mov %eax,-0x8(%rbp)400501: c7 45 f4 f6 ff ff ff movl $0xfffffff6,-0xc(%rbp)400508: 8b 45 f4 mov -0xc(%rbp),%eax40050b: c1 f8 02 sar $0x2,%eax // 算术右移,以1填充40050e: 89 45 f0 mov %eax,-0x10(%rbp)400511: b8 00 00 00 00 mov $0x0,%eax400516: 5d pop %rbp400517: c3 retq 400518: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)40051f: 00
由于算术右移会对有符号数和无符号数进行区分,因此使用算术右移对补码进行操作可以代替一部分的整数运算,对于下面的arith函数
long arith(long x, long y, long z)
{long t1 = x ^ y;long t2 = z * 48;long t3 = t1 & 0x0F0F0F0F;long t4 = t2 - t3;return t4;
}
对应的汇编为
/*
long arith(long x, long y, long z)
x in %rdi, y in %rsi, z in %rdx
*/arith:xorq %rsi, %rdi t1 = x ^ yleaq (%rdx,%rdx,2), %rax 3*zsalq $4, %rax t2 = 16 * (3*z) = 48*zandl $252645135, %edi t3 = t1 & 0x0F0F0F0Fsubq %rdi, %rax Return t2 - t3ret
这里用salq $4, %rax 代替乘法,可以加快运算
5. 特殊的算术操作
两个64位有符号数或者无符号数相乘得到的乘积需要128位来表示。x86-64指令集对128位数的操作提供了一定程度上的支持,Intel将16字节的数称为8字(oct word)
下表是支持产生两个64位数字的全128位乘积以及整数除法的指令
| 指令 | 效果 | 描述 |
| imuq S | R[ %rdx ]:R[ %rax ] ← S × R[ %rax ] | 有符号乘法 |
| mulq S | R[ %rdx ]:R[ %rax ] ← S × R[ %rax ] | 无符号乘法 |
| cqto | R[ %rdx ]:R[ %rax ] ← SignExtend(R[ %rax ]) | 转化为八字 |
| idivq S | R[ %rdx ] ← R[ %rdx ]:R[ %rax ]mod S R[ %rax ] ← R[ %rdx ]:R[ %rax ]÷ S | 有符号除法 |
| divq S | R[ %rdx ] ← R[ %rdx ]:R[ %rax ]mod S R[ %rax ] ← R[ %rdx ]:R[ %rax ]÷ S | 无符号除法 |
两个寄存器%rdx(64位)和%rax(64位)组成一个128位的八字,根据乘积中高部分是否为0设置或清楚CF、OF
对于无符号乘法(mulq)和有符号乘法(imulq)而言,二者都是单操作数乘法指令,都需要将一个参数存放在寄存器%rax中,而另一个则作为指令的源操作数给出,乘积放在寄存器%rdx和%rax中
| %rdx(64位) | %rax(64位) |
下面是一个示例,其中细节见CASPP原书3.5.5小节
#include <inttypes.h>typedef unsigned __int128 uint128_t;void store_uprod(uint128_t *dest, uint64_t x, uint64_t y)
{*dest = x * (uint128_t)y;
}
/*
void store_uprod(uint128_t *dest, uint64_t x, uint64_t y)
dest in %rdi, x in %rsi, y in %rdx
*/store_uprod:movq %rsi, %rax Copy x to multiplicandmulq %rdx Multiply by ymovq %rax, (%rdi) Store lower 8 bytes at destmovq %rdx, 8(%rdi) Store upper 8 bytes at dest+8ret
相关文章:
程序的机器级表示part3——算术和逻辑操作
目录 1.加载有效地址 2. 整数运算指令 2.1 INC 和 DEC 2.2 NEG 2.3 ADD、SUB 和 IMUL 3. 布尔指令 3.1 AND 3.2 OR 3.3 XOR 3.4 NOT 4. 移位操作 4.1 算术左移和逻辑左移 4.2 算术右移和逻辑右移 5. 特殊的算术操作 1.加载有效地址 指令效果描述leaq S, DD…...
基于YOLOV5的钢材缺陷检测
数据和源码见文末 1.任务概述 数据集使用的是东北大学收集的一个钢材缺陷检测数据集,需要检测出钢材表面的6种划痕。同时,数据集格式是VOC格式,需要进行转化,上传的源码中的数据集是经过转换格式的版本。 2.数据与标签配置方法 在数据集目录下,train文件夹下有训练集数据…...
Session与Cookie的区别(三)
中场休息 让我们先从比喻回到网络世界里,HTTP 是无状态的,所以每一个 Request 都是不相关的,就像是对小明来说每一位客人都是新的客人一样,他根本不知道谁是谁。 既然你没办法把他们关联,就代表状态这件事情也不存在。…...
七大设计原则之接口隔离原则应用
目录1 接口隔离原则介绍2 接口隔离原则应用1 接口隔离原则介绍 接口隔离原则(Interface Segregation Principle, ISP)是指用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口。这个原则指导我们在设计接口时…...
【Shell1】shell语法,ssh/build/scp/upgrade,环境变量,自动升级bmc
文章目录1.shell语法:shell是用C语言编写的程序,是用户使用Linux的桥梁,硬件>内核(os)>shell>文件系统1.1 变量:readonly定义只读变量,unset删除变量1.2 函数:shell脚本传递的参数中包含空格&…...
JavaScript HTML DOM - 改变CSS
JavaScript 是一种动态语言,它可以动态地修改网页的外观,并且使用HTML DOM(文档对象模型)可以更方便地控制HTML元素的样式。 JavaScript 通过在HTML DOM中更改CSS属性来更改样式,这些CSS属性包括颜色、位置、字体大小…...
mycat连接mysql 简单配置
mycat三个配置文件位于conf下 可通过Notepad操作 首先配置service.xml中的user标签,设置用户名,密码,查询权限,是否只读等 只是设置了root用户,有所有权限 配置schema.xml <?xml version"1.0"?&g…...
Spring常用注解
文章目录一、Bean交给Spring管理1、Component2、Bean3、Controller4、Service5、Repository6、Configuration7、ComponentScan二、作用域1、Lazy(false)Scope三、依赖注入1、Autowired2、Resource3、Qualifier四、读取配置文件值1、Value一、Bean交给Spring管理 1、Component …...
I.MX6ULL内核开发9:kobject-驱动的基石
目录 一、摘要 二、重点 三、驱动结构模型 四、关键函数分析 kobject_create_and_add()函数 kobject_create()函数 kobject_init()函数 kobject_init_internal()函数 kobject_add()函数 kobject_add_varg&am…...
Docker-harbor私有仓库
一、Harbor概述 1、Harbor的概念 • Harbor是VMware公司开源的企业级Docker Registry项目,其目标是帮助用户迅速搭建一个企业级的Docker Registry服务 • Harbor以 Docker 公司开源的Registry 为基础,提供了图形管理UI、基于角色的访问控制(Role Base…...
Java之动态规划之子序列问题
目录 0.动态规划问题 一.最长递增子序列 1.题目描述 2.问题分析 3.代码实现 二.最长递增子序列 1.题目描述 2.问题分析 3.代码实现 三.最长重复子数组 1.题目描述 2.问题分析 3.代码实现 4.代码的优化(滚动数组) 四.最长公共子序列 1.题目描述 2.问题分析 3.代…...
java ArrayList
目录 一.简单介绍 二.ArrayList的底层结构 2.1ArrayList的底层结构和操作分析 2.ArrayList 底层源码分析 三.ArrayList 方法 四.代码使用方法 一.简单介绍 ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们…...
前端——周总结系列四
1 JS变量与常量 概述 变量:在后续编码过程中会被重新赋值,是不断变化的。常量:固定不变的数据,日常生活比如性别男,代码层面是在编码过程中不会变化的固定数据。 命名规则 变量 可以包含数字,字母&…...
Linux重定向符、管道符讲解
目录 重定向 将命令与文件进行互动 输出重定向 输入重定向 管道符 将命令与命令互动起来 重定向 将命令与文件进行互动 重定向分类 一般情况下,Linux命令运行时都会打开一下三个文件 标准输入文件:stdin文件,文件描述符为0,Li…...
【C++】多态
多态一、多态的概念及定义1.1 虚函数1.2 虚函数重写的特殊情况1.3 override 和 final二、抽象类2.1 概念2.2 用处三、多态的原理3.1 虚函数表3.1.1 虚函数与虚表的位置3.2 多态的原理3.3 静态绑定和动态绑定四、单/多继承的虚函数表4.1 单继承的虚函数表4.2 多继承的虚函数表一…...
分布式项目-品牌管理(5、6)
【今日成果】: //使用阿里云OSS服务: //使用v-if如果地址没有就不显示 , 如果地址错误图片就显示不出来; 【快速回顾】: 任何数据的删除都不要使用物理上的删除,应当使用逻辑上的删除!&…...
自定义ESLint规则开发与使用
自定义eslint及使用 项目结构 |-eslint-plugin-demo //自定义eslint插件项目 | |-demo-app // 使用自定义eslint的测试应用 |-README.md 项目效果: github项目地址 自定义ESLint环境准备 安装脚手架 执行下列命令来安装开发eslint的脚手架。 yo(y…...
【JavaScript】35_包装类与垃圾回收机制
10、包装类 在JS中,除了直接创建原始值外,也可以创建原始值的对象 通过 new String() 可以创建String类型的对象 通过 new Number() 可以创建Number类型的对象 通过 new Boolean() 可以创建Boolean类型的对象 但是千万不要这么做 包装类࿱…...
【CS224W】(task3)NetworkX工具包实践
note 节点可以为任意可哈希的对象,比如字符串、图像、XML对象,甚至另一个Graph、自定义的节点对象。通过这种方式可以自由灵活地构建:图为节点、文件为节点、函数为节点,等灵活的图形式。暂时省略:【B5】计算机网络图…...
ansible的模块详解
ansible 的概述 什么是ansible Ansible是一款为类Unix系统开发的自由开源的配置和自动化工具。 它用Python写成,类似于saltstack和Puppet,但是有一个不同和优点是我们不需要在节点中安装任何客户端。 它使用SSH来和节点进行通信。Ansible基于 Python…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
