程序的机器级表示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…...
使用现代 Java 技术栈构建企业级 AI 应用
使用现代 Java 技术栈构建企业级 AI 应用 引言 随着人工智能技术的快速发展,企业级 AI 应用的需求也迅速增长。Java 作为一门成熟的企业级编程语言,其生态系统在 AI 应用开发中扮演着重要角色。本文将探讨如何利用 Java 技术栈构建生产级 AI 应用&#x…...
教你 .NET Core API 怎么和数据库表一一对应
不用复杂理论,直接照做就能成功! 一、核心规则(记住这 4 句) 类 = 表 类名 = 表名 属性 = 字段 属性名 = 字段名 二、一步一步教你对应(超级简单) 1)数据库有一张表 → 你就写一个类 例如你数据库里有表: sql Users (Id int primary key identity,Name nvarchar(5…...
百川2-13B-4bits量化版对比测试:OpenClaw日常任务执行效率报告
百川2-13B-4bits量化版对比测试:OpenClaw日常任务执行效率报告 1. 测试背景与动机 最近在折腾OpenClaw自动化工作流时,发现一个棘手问题:当任务链条较长时,本地部署的大模型显存占用会飙升到16GB以上,导致我的RTX 30…...
Windows上搭建PostgreSQL监控神器:Grafana+Prometheus+Postgres_Exporter保姆级干货教程
❓想要实时掌握 PostgreSQL 数据库的运行状态? 👀想知道复制延迟、锁等待这些核心指标? 🆒这里是Moshow的「CSDN https://zhengkai.blog.csdn.net/」 🚀这篇文章带你从零开始,在 Windows 上搭建一套企业…...
低延迟多场景的Windows音频捕获解决方案:win-capture-audio实战指南
低延迟多场景的Windows音频捕获解决方案:win-capture-audio实战指南 【免费下载链接】win-capture-audio An OBS plugin that allows capture of independant application audio streams on Windows, in a similar fashion to OBSs game capture and Discords appli…...
为什么你的USB设备总接触不良?A/B型接口物理结构对比与耐久性测试
为什么你的USB设备总接触不良?A/B型接口物理结构对比与耐久性测试 每次给手机充电都要反复调整角度,打印机线稍微碰一下就断开连接——这些恼人的USB接口问题,本质上都是物理结构设计的差异在作祟。作为消费电子领域最基础的连接标准…...
HunyuanVideo-Foley音效生成:支持SMPTE时间码对齐视频关键帧
HunyuanVideo-Foley音效生成:支持SMPTE时间码对齐视频关键帧 1. 产品概述 HunyuanVideo-Foley是一款专为影视后期制作设计的AI音效生成工具,其核心创新在于支持SMPTE时间码精确对齐视频关键帧。这意味着音效师可以基于视频时间轴上的特定帧,…...
【adb端口5555】烽火hg680系列安卓9线刷全攻略:告别强制升级与花屏困扰
1. 烽火HG680系列机顶盒的痛点与解决方案 最近在折腾烽火HG680-GY和HG680-GC这两款机顶盒的朋友应该都深有体会,官方系统用着用着就会弹出强制升级提示,有时候还会莫名其妙出现花屏问题。作为一个折腾过不下20台烽火盒子的老玩家,我太理解这种…...
Quartus-II 9.0实战:从半加器到4位加法器的数字逻辑设计全流程解析
1. 半加器设计:数字逻辑的起点 半加器是数字电路设计中最基础的加法单元,理解它的工作原理对后续学习全加器和多位加法器至关重要。半加器之所以称为"半",是因为它只能处理两个1位二进制数的相加,不考虑来自低位的进位输…...
电工必看:正弦交流电路中的相量法实战技巧(附计算示例)
电工必看:正弦交流电路中的相量法实战技巧(附计算示例) 在电气工程领域,正弦交流电路的分析是每位电工和电气工程师必须掌握的核心技能。面对复杂的电路计算,传统的三角函数解析法往往让从业者陷入繁琐的运算泥潭。相量…...
