程序的机器级表示part3——算术和逻辑操作

news2024/9/24 17:09:09

目录

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 ← &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   %rbp
  4004ee:	48 89 e5             	mov    %rsp,%rbp
  4004f1:	c7 45 f4 0a 00 00 00 	movl   $0xa,-0xc(%rbp)
  4004f8:	48 8d 45 f4          	lea    -0xc(%rbp),%rax  // 取a的地址放进%rax
  4004fc:	48 89 45 f8          	mov    %rax,-0x8(%rbp)
  400500:	b8 00 00 00 00       	mov    $0x0,%eax
  400505:	5d                   	pop    %rbp
  400506:	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*y
    leaq (%rdx,%rdx,2), %rdx     z + 2*z = 3*z
    leaq (%rax,%rdx,4), %rax     (x+4*y) + 4*(3*z) = x + 4*y + 12*z
    ret

因此,leaq指令也能完成加法和有限的乘法计算,需要注意的一点是,寻址模式中的比例因子只能是1,2,4,8,说明leaq指令完成乘法时,也只能与1,2,4,8相乘,上面代码中,第二行不能使用 leaq(%rax, %rdx, 12) 一步完成计算,而是要分成两步也正是因为这个原因

2. 整数运算指令

指令效果描述
INC    DD ← D + 1加1
DEC    DD ← D - 1减1
NEG    DD ← - D 取负
NOT    DD ← ~ D 取补
ADD    S, DD ← D + S
SUB    S, DD ← D - S
IMUL    S, DD ← 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);      10

    return 0;
}
00000000004004ed <main>:
  4004ed:	55                   	push   %rbp
  4004ee:	48 89 e5             	mov    %rsp,%rbp
  4004f1:	c7 45 fc 0a 00 00 00 	movl   $0xa,-0x4(%rbp)
  4004f8:	8b 45 fc             	mov    -0x4(%rbp),%eax
  4004fb:	ff c0                	inc    %eax             // 把%eax中的值加1
  4004fd:	89 45 fc             	mov    %eax,-0x4(%rbp)
  400500:	8b 45 fc             	mov    -0x4(%rbp),%eax
  400503:	ff c8                	dec    %eax             // 把%eax中的值减1
  400505:	89 45 fc             	mov    %eax,-0x4(%rbp)
  400508:	b8 00 00 00 00       	mov    $0x0,%eax
  40050d:	5d                   	pop    %rbp
  40050e:	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   %rbp
  4004ee:	48 89 e5             	mov    %rsp,%rbp
  4004f1:	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,%eax
  400500:	5d                   	pop    %rbp
  400501:	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   %rbp
  4004ee:	48 89 e5             	mov    %rsp,%rbp
  4004f1:	c7 45 fc 0a 00 00 00 	movl   $0xa,-0x4(%rbp)    // int a = 10;
  4004f8:	8b 45 fc             	mov    -0x4(%rbp),%eax
  4004fb:	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),%eax
  400504:	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),%eax
  40050d:	0f af 45 f8          	imul   -0x8(%rbp),%eax    // a = a * b;
  400511:	89 45 fc             	mov    %eax,-0x4(%rbp)
  400514:	5d                   	pop    %rbp
  400515:	c3                   	retq   
  400516:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)
  40051d:	00 00 00 

3. 布尔指令

C语言里存在位操作符

分别对应下面的指令 

指令效果描述
AND    S, DD ← D & S 
OR    S, DD ← D | 1
XOR    S, DD ← D ^ S异或
NOT    DD ← ~ 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 00001010
    int y = x & 8;   // 00000000 00000000 00000000 00001000

    return 0;
}

00000000004004ed <main>:
  4004ed:	55                   	push   %rbp
  4004ee:	48 89 e5             	mov    %rsp,%rbp
  4004f1:	c7 45 fc 0a 00 00 00 	movl   $0xa,-0x4(%rbp)    // int x = 10;
  4004f8:	8b 45 fc             	mov    -0x4(%rbp),%eax
  4004fb:	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,%eax
  400506:	5d                   	pop    %rbp
  400507:	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 00001010
    int y = x | 8;   // 00000000 00000000 00000000 00001000

    return 0;
}

00000000004004ed <main>:
  4004ed:	55                   	push   %rbp
  4004ee:	48 89 e5             	mov    %rsp,%rbp
  4004f1:	c7 45 fc 0a 00 00 00 	movl   $0xa,-0x4(%rbp)    // int x = 10;
  4004f8:	8b 45 fc             	mov    -0x4(%rbp),%eax
  4004fb:	83 c8 08             	or     $0x8,%eax          // int y = x | 8
  4004fe:	89 45 f8             	mov    %eax,-0x8(%rbp)
  400501:	b8 00 00 00 00       	mov    $0x0,%eax
  400506:	5d                   	pop    %rbp
  400507:	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 00001010
    int y = x ^ 8;   // 00000000 00000000 00000000 00001000

    return 0;
}

00000000004004ed <main>:
  4004ed:	55                   	push   %rbp
  4004ee:	48 89 e5             	mov    %rsp,%rbp
  4004f1:	c7 45 fc 0a 00 00 00 	movl   $0xa,-0x4(%rbp)    // int x = 10;
  4004f8:	8b 45 fc             	mov    -0x4(%rbp),%eax
  4004fb:	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,%eax
  400506:	5d                   	pop    %rbp
  400507:	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 00001010
    int y = ~x;      // 11111111 11111111 11111111 11110101

    return 0;
}

00000000004004ed <main>:
  4004ed:	55                   	push   %rbp
  4004ee:	48 89 e5             	mov    %rsp,%rbp
  4004f1:	c7 45 fc 0a 00 00 00 	movl   $0xa,-0x4(%rbp)    // int x = 10;
  4004f8:	8b 45 fc             	mov    -0x4(%rbp),%eax
  4004fb:	f7 d0                	not    %eax               // ~x;
  4004fd:	89 45 f8             	mov    %eax,-0x8(%rbp)    // int y = ~x;
  400500:	b8 00 00 00 00       	mov    $0x0,%eax
  400505:	5d                   	pop    %rbp
  400506:	c3                   	retq   
  400507:	66 0f 1f 84 00 00 00 	nopw   0x0(%rax,%rax,1)
  40050e:	00 00 

4. 移位操作

C语言中移位操作符分为左移操作符(<<)和右移操作符(>>),而移位操作又分左移和右移

指令效果描述
SAL    k, DD ← D << k算术左移
SHL    k, DD ← D << k

逻辑左移

(等同SAL)

SAR    k, DD ← D >> k算数右移
SHL    k, DD ← D >> k逻辑右移

移位操作

  1. 第一个操作数是移位量k,也就是二进制位移动的位数
  2. 第二个操作数是要移位的数

注意:移位量可以是一个立即数,或者放在单字节寄存器%cl中(规定了只能放在这里) 

%cl长8位,可表示0~255,因此移位量的最大可以达到255位,但是显然没有这么长的数据类型,因此实际上移位操作是根据要移动的数的位数来决定取%cl的哪些值的,

x86-64中,移位操作对w位长的数据值进行操作,移位量是由%cl寄存器的低m位决定的,这里2的m次方等于w,高位会被忽略 

比如此时%cl内是0xFF

%cl1111 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 00001010
    int y = x << 2;  // 00000000 00000000 00000000 00101000
   
    return 0;
}

00000000004004ed <main>:
  4004ed:	55                   	push   %rbp
  4004ee:	48 89 e5             	mov    %rsp,%rbp
  4004f1:	c7 45 fc 0a 00 00 00 	movl   $0xa,-0x4(%rbp)     // int x = 10;
  4004f8:	8b 45 fc             	mov    -0x4(%rbp),%eax
  4004fb:	c1 e0 02             	shl    $0x2,%eax           // x << 2
  4004fe:	89 45 f8             	mov    %eax,-0x8(%rbp)     // int y = x << 2;
  400501:	b8 00 00 00 00       	mov    $0x0,%eax
  400506:	5d                   	pop    %rbp
  400507:	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 00001010
    int y1 = x1 >> 2;  // 00000000 00000000 00000000 00000010

    int x2 = -10;      // 11111111 11111111 11111111 11110110
    int y2 = x2 >> 2;  // 11111111 11111111 11111111 11111101

    return 0;
}

00000000004004ed <main>:
  4004ed:	55                   	push   %rbp
  4004ee:	48 89 e5             	mov    %rsp,%rbp
  4004f1:	c7 45 fc 0a 00 00 00 	movl   $0xa,-0x4(%rbp)
  4004f8:	8b 45 fc             	mov    -0x4(%rbp),%eax
  4004fb:	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),%eax
  40050b:	c1 f8 02             	sar    $0x2,%eax          // 算术右移,以1填充
  40050e:	89 45 f0             	mov    %eax,-0x10(%rbp)
  400511:	b8 00 00 00 00       	mov    $0x0,%eax
  400516:	5d                   	pop    %rbp
  400517:	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 ^ y
    leaq (%rdx,%rdx,2), %rax    3*z
    salq $4, %rax               t2 = 16 * (3*z) = 48*z
    andl $252645135, %edi       t3 = t1 & 0x0F0F0F0F
    subq %rdi, %rax             Return t2 - t3
    ret

这里用salq $4, %rax 代替乘法,可以加快运算

5. 特殊的算术操作 

两个64位有符号数或者无符号数相乘得到的乘积需要128位来表示。x86-64指令集对128位数的操作提供了一定程度上的支持,Intel将16字节的数称为8字(oct word)

下表是支持产生两个64位数字的全128位乘积以及整数除法的指令

指令效果描述
imuq    SR[ %rdx ]:R[ %rax ] ← S × R[ %rax ] 有符号乘法
mulq    SR[ %rdx ]:R[ %rax ] ← S × R[ %rax ] 

无符号乘法

cqtoR[ %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 multiplicand
    mulq %rdx Multiply by y
    movq %rax, (%rdi) Store lower 8 bytes at dest
    movq %rdx, 8(%rdi) Store upper 8 bytes at dest+8
    ret

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/340701.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【项目实战】32G的电脑启动IDEA一个后端服务要2min!谁忍的了?

一、背景 本人电脑性能一般&#xff0c;但是拥有着一台高性能的VDI&#xff08;虚拟桌面基础架构&#xff09;&#xff0c;以下是具体的配置 二、问题描述 但是&#xff0c;即便是拥有这么高的性能&#xff0c;每次运行基于Dubbo微服务架构下的微服务都贼久&#xff0c;以下…

使用太极taichi写一个只有一个三角形的有限元

公式来源 https://blog.csdn.net/weixin_43940314/article/details/128935230 GAME103 https://games-cn.org/games103-slides/ 初始化我们的三角形 全局的坐标范围为0-1 我们的三角形如图所示 ti.kernel def init():X[0] [0.5, 0.5]X[1] [0.5, 0.6]X[2] [0.6, 0.5]x[0…

每天10个前端小知识 【Day 12】

&#x1f469; 个人主页&#xff1a;不爱吃糖的程序媛 &#x1f64b;‍♂️ 作者简介&#xff1a;前端领域新星创作者、CSDN内容合伙人&#xff0c;专注于前端各领域技术&#xff0c;成长的路上共同学习共同进步&#xff0c;一起加油呀&#xff01; ✨系列专栏&#xff1a;前端…

I.MX6ULL内核开发9:kobject-驱动的基石

目录 一、摘要 二、重点 三、驱动结构模型 四、关键函数分析 kobject_create_and_add()函数 kobject_create()函数 kobject_init&#xff08;&#xff09;函数 kobject_init_internal(&#xff09;函数 kobject_add&#xff08;&#xff09;函数 kobject_add_varg&am…

JAVA集合专题4 ——ArrayDeque + BlockingQueue

目录ArrayDeque的特点BlockingQueue什么是BlockingQueue?什么叫阻塞队列?阻塞队列的应用场景是什么?BlockingQueue的阻塞方法是什么?BlockingQueue的四类方法codecode2ArrayDeque的特点 ArrayDeque是Deque接口子实现ArrayDeque数据结构可以表示为: 队列、双端队列、栈Arra…

C语言学习笔记(三): 选择结构程序设计

if语句 if(){} if (a1){printf("hehe");} //单独一个ifif(){}else{} int a 1, b 2;if (a b) {printf("haha"); //if else}else{printf("hehe");}if(){}else if(){} int a 1, b 2;if (a b) {printf("haha");}else if (a …

io的基本原理-nio

io的基本原理-nioio读写的基本原理io的模型1.同步阻塞IO2. 同步非阻塞IO3. IO多路复用4. 异步IO5.半同步半阻塞半异步IOnio是什么&#xff1f;NIO 的核心原理&#xff1a;java版代码cpp版本I/O&#xff08;Input/Output&#xff09;是计算机科学中指计算机和外部设备进行数据交…

Java Set集合

7 Set集合 7.1 Set集合的概述和特点 Set集合的特点 不包含重复元素的集合没有带索引的方法&#xff0c;所以不能使用普通for循环 Set集合是接口通过实现类实例化&#xff08;多态的形式&#xff09; HashSet&#xff1a;添加的元素是无序&#xff0c;不重复&#xff0c;无索引…

线程和QObjects

QObject的可重入性&#xff1a; QThread继承了QObject&#xff0c;它发出信号以指示线程开始或完成执行&#xff0c;并提供一些插槽。 QObjects可以在多个线程中使用发出调用其他线程中槽的信号&#xff0c;并将事件发布到在其他线程中“活动”的对象。这是可能的&#xff0…

redis可视工具AnotherRedisDesktopManager的使用

redis可视工具AnotherRedisDesktopManager的使用 简介 Another Redis DeskTop Manager 是一个开源项目&#xff0c;提供了以可视化的方式管理 Redis 的功能&#xff0c;可供免费下载安装&#xff0c;也可以在此基础上进行二次开发&#xff0c;主要特点有&#xff1a; 支持 W…

Matlab中安装NURBS工具箱及使用

文章目录前言一、NURBS工具箱的安装1 打开matlab&#xff0c;点击附加功能2 输入nurbs3 下载后压缩包解压4 将解压后的文件夹放到matlab文件夹的toolbox文件夹里面5 选择“预设路径”上方的“预设”二、NURBS工具箱的使用2.1 NURBS 结构&#xff1a;2.2 对NURBS工具箱的初步理解…

关于表的操作 数据库(3)

目录 前期准备工作&#xff1a; 一、单表查询&#xff1a; 二、多表查询&#xff1a; 前期准备工作&#xff1a; 修改数据库的配置文件&#xff0c;&#xff0c;使其可以显示库名&#xff0c;其中//d代表当前使用的数据库名 注&#xff1a;vim /etc/my.cnf.d/mysql-server.c…

Session与Cookie的区别(四)

咖啡寄杯的烦恼 虽然店里生意还可以&#xff0c;但小明无时无刻不想着怎么样发大财赚大钱&#xff0c;让店里的生意变得更好。 他观察到最近好多便利商店开始卖起了咖啡&#xff0c;而且时不时就买一送一或是第二件半价&#xff0c;并且贴心地提供了寄杯的服务。 寄杯就是指说你…

《剑指offer》:数组部分

一、数组中重复的数字题目描述&#xff1a;在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的&#xff0c;但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如&#xff0c;如果输入长度为7的数组{2,3,1…

C语言fscanf和fprintf函数的用法详解

fscanf() 和 fprintf() 函数与前面使用的 scanf() 和 printf() 功能相似&#xff0c;都是格式化读写函数&#xff0c;两者的区别在于 fscanf() 和 fprintf() 的读写对象不是键盘和显示器&#xff0c;而是磁盘文件。这两个函数的原型为&#xff1a;int fscanf ( FILE *fp, char …

【力扣-LeetCode】1138. 字母板上的路径-C++题解

1138. 字母板上的路径难度中等98收藏分享切换为英文接收动态反馈我们从一块字母板上的位置 (0, 0) 出发&#xff0c;该坐标对应的字符为 board[0][0]。在本题里&#xff0c;字母板为board ["abcde", "fghij", "klmno", "pqrst", &quo…

点云转3D网格【Python】

推荐&#xff1a;使用 NSDT场景设计器 快速搭建 3D场景。 在本文中&#xff0c;我将介绍我的 3D 表面重建过程&#xff0c;以便使用 Python 从点云快速创建网格。 你将能够导出、可视化结果并将结果集成到您最喜欢的 3D 软件中&#xff0c;而无需任何编码经验。 此外&#xff0…

总投资超500亿,广州白云机场三期扩建工程的IT投资更吸引人

【科技明说 | 每日看点】2023年基建大工程计划出台&#xff0c;广州白云机场三期将落实百亿元投资引发业内关注。据悉&#xff0c;广州白云机场三期扩建工程投资达537.7亿元&#xff0c;计划于2025年建成投产。这是中国民航历史上规模最大的改扩建工程&#xff0c;其扩建工程今…

TC3xx FlexRay™ 协议控制器 (E-Ray)-01

1 FlexRay™ 协议控制器 (E-Ray) E-Ray IP 模块根据为汽车应用开发的 FlexRay™ 协议规范 v2.1 执行通信【performs communication according to the FlexRay™ 1) protocol specification v2.1】。使用最大指定时钟&#xff0c;比特率可以编程为高达 10 Mbit/s 的值。连接到物…

Fluent Python 笔记 第 5 章 一等函数

在 Python 中&#xff0c;函数是一等对象。编程语言理论家把“一等对象”定义为满足下述条件的程 序实体: 在运行时创建能赋值给变量或数据结构中的元素 • 能作为参数传给函数能作为函数的返回结果 5.1 把函数视作对象 会用 map。 5.2 高阶函数 接受函数为参数&#xff0…