5.9 汇编语言:浮点数操作指令

微软技术分享 微软全球最有价值专家
全栈领域优质创作者
博客专家认证
2023-11-27 08:40:36

汇编语言是一种面向机器的低级语言,用于编写计算机程序。汇编语言与计算机机器语言非常接近,汇编语言程序可以使用符号、助记符等来代替机器语言的二进制码,但最终会被汇编器编译成计算机可执行的机器码。

浮点运算单元是从80486处理器开始才被集成到CPU中的,该运算单元被称为FPU浮点运算模块,FPU不使用CPU中的通用寄存器,其有自己的一套寄存器,被称为浮点数寄存器栈,FPU将浮点数从内存中加载到寄存器栈中,完成计算后在回写到内存中。

FPU有8个可独立寻址的80位寄存器,分别名为R0-R7他们以堆栈的形式组织在一起,栈顶由FPU状态字中的一个名为TOP的域组成,对寄存器的引用都是相对于栈顶而言的,栈顶通常也被叫做ST(0)最后一个栈底则被记作ST(7)其使用方式与堆栈一致。

浮点数运算通常会使用一些更长的数据类型,如下就是MASM汇编器定义的常用数据类型.

.data
  var1 QWORD  10.1    ; 64位整数
  var2 TBYTE  10.1    ; 80位(10字节)整数
  var3 REAL4  10.2    ; 32位(4字节)短实数
  var4 REAL8  10.8    ; 64位(8字节)长实数
  var5 REAL10 10.10   ; 80位(10字节)扩展实数

此外浮点数对于指令的命名规范也遵循一定的格式,浮点数指令总是以F开头,而指令的第二个字母则表示操作位数,例如:B表示二十进制操作数,I表示二进制整数操作,如果没有指定则默认则是针对实数的操作fld等.

9.1 FLD/FSTP

FLD 和 FSTP 是x86架构处理器中的浮点操作指令,FLD指令用于将浮点数从内存装载进浮点寄存器,或者FSTP指令从浮点寄存器存储到内存中。

FLD 指令用于从内存中读取单精度浮点数(32位)或双精度浮点数(64位),并将其存储到浮点栈中。FLD 指令的语法如下:

FLD source

其中,source 可以是内存地址、寄存器或立即数。例如,要将双精度浮点数3.14159存储到浮点栈中,可以使用以下指令:

movsd xmm0, [pi]      ; 将pi常量的值放入xmm0寄存器中
movsd [esp], xmm0     ; 将xmm0寄存器中的值存储到栈顶
fld qword ptr [esp]   ; 将栈顶的值从内存中装载到浮点栈中

其中,xmm0 是双精度浮点寄存器,pi 是一个双精度浮点常量的地址,esp 是堆栈指针寄存器,qword ptr标记用于指示要读取的内存单元的数据大小。

FSTP 指令用于将浮点栈顶的值弹出,并将其存储到内存中。FSTP指令的语法如下:

FSTP destination

其中,destination 可以是内存地址、寄存器或立即数。例如,将浮点栈顶的值存储到内存单元 x 中,可以使用以下指令:

fstp qword ptr [x]    ; 将浮点栈顶的值存储到 x 变量的内存单元中

需要注意,FSTP 指令会将浮点栈顶部的值弹出,在栈顶的值被存储到目标地址之后,浮点栈顶部的指针将自动下移。

  .386p
  .model flat,stdcall
  option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib

.data
  var1 QWORD 10.0
  var2 QWORD 20.0
  var3 QWORD 30.0
  var4 QWORD 40.0
  result QWORD ?
.code
  main PROC
    ; 初始化浮点单元
    finit
    
    ; 依次将数据入栈
    fld qword ptr ds:[var1]
    fld qword ptr ds:[var2]
    fld qword ptr ds:[var3]
    fld qword ptr ds:[var4]
    
    ; 获取当前ST(0)栈帧元素
    fst qword ptr ds:[result]
    
    ; 从栈中弹出元素
    fstp qword ptr ds:[result]
    fstp qword ptr ds:[result]
    fstp qword ptr ds:[result]
    fstp qword ptr ds:[result]
    int 3
  main ENDP
END main

压栈指令同样支持变址寻址的方式,如下代码案例中我们可以通过循环将一个数组压入浮点数寄存器,其中使用FLD指令时压入一个浮点实数,而FILD则是将实数转换为双精度浮点数后压入堆栈。

  .386p
  .model flat,stdcall
  option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib

.data
  Array QWORD 10.0,20.0,30.0,40.0,50.0
  Count DWORD ?
  Result QWORD ?
.code
  main PROC
  
    ; 初始化浮点单元
    finit
    mov dword ptr ds:[Count],0
    jmp L1

  L2: mov eax,dword ptr ds:[Count]
    add eax,1
    mov dword ptr ds:[Count],eax

  L1: mov eax,dword ptr ds:[Count]
    cmp eax,5
    jge lop_end
    
    ; 使用此方式压栈
    fld qword ptr ds:[Array + eax * 8]   ; 压入浮点实数
    fild qword ptr ds:[Array + eax * 8]  ; 压入双精度浮点数

    jmp L2
  lop_end:
    int 3
  main ENDP
END main

9.2 FCHS/FABS

FCHS 指令是x86架构处理器中的浮点数操作指令,该指令可用于把ST(0)中值的符号变反,FABS 指令用于将浮点数的值取绝对值。这两条指令的操作对象是浮点寄存器,而不是浮点栈。因此,它并未涉及堆栈操作或操作数的传递。在使用 FCHS 和 FABS 指令时,需要使用浮点操作指令前缀 F 来标识它们是浮点数操作指令。

  .386p
  .model flat,stdcall
  option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib

.data
  Array QWORD 10.0,20.0,30.0,40.0,50.0
  Result QWORD ?
  
  szFmt BYTE 'ST寄存器: %f ',0dh,0ah,0 
.code
  main PROC
    ; 初始化压栈
    finit
    fld qword ptr ds:[Array]
    fld qword ptr ds:[Array + 8]
    fld qword ptr ds:[Array + 16]
    fld qword ptr ds:[Array + 24]
    fld qword ptr ds:[Array + 32]

    ; 对ST(0)数据取反 (不影响浮点堆栈)
    fchs                                               ; 对ST(0)取反
    fchs                                               ; 再次取反
    fst qword ptr ds:[Result]                          ; 取ST(0)赋值到Result
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    
    ; 循环将数组取反后回写如Array中
    mov ecx,5
  S1:
    fchs
    fstp qword ptr ds:[Array + ecx * 8]
    loop S1
    
    ; 读入Array中的数据到ST寄存器
    mov ecx,5
  S2:
    fld qword ptr ds:[Array + ecx * 8]
    loop S2
    
    ; 通过FABS取绝对值,并反写会Array中
    mov ecx,5
  S3:
    fabs                                  ; 取ST(0)的绝对值
    fstp qword ptr ds:[Array + ecx * 8]   ; 反写
    loop S3
    
    int 3
  main ENDP
END main

9.3 FADD/FADDP/FIADD

浮点数加法系列指令,该系列可分为FADD/FADDP/FIADD,这些指令分别针对不同的场景使用,此外还会区分无操作数模式,寄存器操作数,内存操作数,整数相加等。这些指令用于不同的场景下进行操作,如下所述:

FADD 指令用于将两个浮点数相加,并将结果存储到浮点寄存器中。FADD指令支持多种操作数类型,包括无操作数模式、寄存器操作数和内存操作数等。例如,将一个双精度浮点数和一个32位整数相加,可以使用以下指令:

fld qword ptr [x]    ; 将双精度浮点数x装载到栈顶
fiadd dword ptr [y]  ; 将32位整数y装载到浮点寄存器中,并与栈顶的浮点数相加
fstp qword ptr [z]   ; 将浮点栈顶的值存储到双精度浮点数z中

FADDP 指令也是用于将两个浮点数相加,但是会将结果弹出并存储到目标寄存器或内存中。FADDP指令与FADD指令最大的区别在于它弹出了浮点栈顶的值。例如,将两个单精度浮点数相加并将结果存储到内存中,可以使用以下指令:

fld dword ptr [x]    ; 将单精度浮点数x1装载到栈顶
fadd dword ptr [y]   ; 将单精度浮点数x2装载到栈顶,并与栈顶的数相加
fstp dword ptr [z]   ; 将浮点栈顶的值存储到单精度浮点数z中,同时弹出栈顶

FIADD 指令用于将一个整数加到浮点寄存器的值中。与FADD指令不同,其支持的数据类型只有整数类型,而没有浮点数类型。使用FIADD指令时,要将操作数用一个寄存器或内存地址表示。例如,将一个16位有符号整数加到浮点数中,可以使用以下指令:

fild word ptr [x]   ; 将16位有符号整数x装载到浮点寄存器中
fadd dword ptr [y]  ; 将32位浮点数y装载到栈顶,并与浮点寄存器中的整数相加
fstp dword ptr [z]  ; 将浮点栈顶的值存储到双精度浮点数z中

如下汇编代码将分别总结四种不同的浮点数计算方式,读者可自行根据提示信息理解这其中的含义。

  • 第一种:无操作数模式,执行FADD时,ST(0)寄存器和ST(1)寄存器相加后,结果临时存储在ST(1)中,然后将ST(0)弹出堆栈,最终结果就会存储在栈顶部,使用FST指令即可取出来。
  • 第二种:则是两个浮点寄存器相加,最后的结果会存储在源操作数ST(0)中。
  • 第三种:则是内存操作数,就是ST寄存器与内存相加。
  • 第四种:是与整数相加,默认会将整数扩展为双精度,然后在于ST(0)相加。
  .386p
  .model flat,stdcall
  option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib

.data
  Array  QWORD 10.0,20.0,30.0,40.0,50.0
  IntA   DWORD 10
  Result QWORD ?
  
  szFmt BYTE 'ST寄存器: %f ',0dh,0ah,0 
.code
  main PROC
    finit
    fld qword ptr ds:[Array]
    fld qword ptr ds:[Array + 8]
    fld qword ptr ds:[Array + 16]
    fld qword ptr ds:[Array + 24]
    fld qword ptr ds:[Array + 32]
    
    ; 第一种:无操作数 fadd = faddp
    ;fadd
    ;faddp
    
    ; 第二种:两个浮点寄存器相加
    fadd st(0),st(1)          ; st(0) = st(0) + st(1)
    fst qword ptr ds:[Result] ; 取出结果
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    
    fadd st(0),st(2)          ; st(0) = st(0) + st(2)
    fst qword ptr ds:[Result] ; 取出结果
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    
    ; 第三种:寄存器与内存相加
    fadd qword ptr ds:[Array] ; st(0) = st(0) + Array
    fst qword ptr ds:[Result] ; 取出结果
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    
    fadd real8 ptr ds:[Array + 8]
    fst qword ptr ds:[Result] ; 取出结果
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    
    ; 第四种:与整数相加
    fiadd dword ptr ds:[IntA]
    fst qword ptr ds:[Result] ; 取出结果
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    int 3
  main ENDP
END main

9.4 FSUB/FSUBP/FISUB

x86架构处理器的浮点数减法指令有FSUB/FSUBP/FISUB该系列指令从目的操作数中减去原操作数,把差存储在目的操作数中,目的操作数必须是ST寄存器,源操作数可以是寄存器或内存,运算的过程与加法指令完全一致。

FSUB指令从浮点数寄存器或内存中减去一个浮点数,并将结果存储到浮点寄存器中。语法如下:

FSUB destination, source

其中, destination 表示目的寄存器或内存地址,source 表示源寄存器或内存地址。例如,要将浮点寄存器ST(0)中的值减去双精度浮点数 x ,并将结果存储回ST(0),则可以使用以下指令:

FLD qword ptr [x]
FSUB ST(0), ST(0)

FSUBP指令也是减法指令,但不同于FSUB,它不需要第一个操作数,而是将栈顶的两个浮点数相减。将栈顶的两个浮点数相减后,FSUBP指令将弹出栈顶部的浮点数,将结果存储在次栈顶的浮点寄存器中。语法如下:

FSUBP destination

其中,destination可以是寄存器或内存地址。例如,要将浮点寄存器ST(0)中的值减去双精度浮点数 x ,并将结果存储到内存地址 z 中,则可以使用以下指令:

FLD qword ptr [x]
FSUBP ST(1), ST(0)
FSTP qword ptr [z]

FISUB指令用于将有符号整数从浮点数中减去。它从存储有符号整数的内存地址或寄存器中装载整数值,并将其作为源操作数,从浮点寄存器中的另一个浮点数中减去。FISUB指令的语法类似于FSUB指令,如下所示:

FISUB destination, source

其中, destination 表示目的寄存器或内存地址,source 表示有符号整数存储的寄存器或内存地址。例如,要将浮点寄存器 ST(0) 中的值减去 16位来源于内存中的有符号整数 y ,并将结果存储回 ST(0) 中,则可以使用以下指令:

FILD word ptr [y]
FSUB ST(0), ST(0)

接着读者看如下案例,这里准备了一个简单的汇编案例,通过四种不同的方式实现了汇编语言中的浮点数减法运算,读者可自行编译并理解其中的实现原理;

  .386p
  .model flat,stdcall
  option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib

.data
  Array      QWORD 10.0,20.0,30.0,40.0,50.0
  IntQWORD   QWORD 20
  Result QWORD ?
  
  szFmt BYTE 'ST寄存器: %f ',0dh,0ah,0 
.code
  main PROC
    finit
    fld qword ptr ds:[Array]
    fld qword ptr ds:[Array + 8]
    fld qword ptr ds:[Array + 16]
    fld qword ptr ds:[Array + 24]
    fld qword ptr ds:[Array + 32]
    
    ; 第一种:无操作数减法
    ;fsub
    ;fsubp                         ; st(0) = st(0) - st(1)
    
    ; 第二种:两个浮点数寄存器相减
    fsub st(0),st(1)               ; st(0) = st(0) - st(1)
    fst qword ptr ds:[Result]
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    
    ; 第三种:寄存器与内存相减
    fsub qword ptr ds:[Array]      ; st(0) = st(0) - Array
    fst qword ptr ds:[Result]
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    
    ; 第四种:与整数相减
    fisub dword ptr ds:[IntQWORD]  ; st(0) = st(0) - IntQWORD
    fst qword ptr ds:[Result]
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    int 3
  main ENDP
END main

9.5 FMUL/FMULP/FIMUL

针对浮点数乘法指令有三种FMUL/FMULP/FIMUL第一个指令用于将堆栈上的浮点数相乘返回值放入到堆栈上,第二个指令则是相乘后将结果从堆栈中弹出,第三个指令则是将浮点数相乘并将结果存储回堆栈中,针对浮点数乘法指令总结如下:

  • FMUL指令:将堆栈上的两个浮点数相乘,并将结果存储回堆栈中。它可以只在ST0ST1之间执行乘法操作。例如,执行FMUL ST1, ST0将ST0和ST1中的两个数相乘,并将结果存储回ST1中。 FMUL指令使用栈操作数。

  • FMULP指令:将堆栈上的两个浮点数相乘,但是不同于FMUL,它会从栈中弹出一个浮点数。例如,执行FMULP ST1, ST0将ST0和ST1中的两个数相乘,并将结果存储回ST1中,然后将ST0从堆栈中弹出。 FMULP指令使用栈操作数。

  • FIMUL指令:将堆栈上的两个浮点数(或整数)相乘,并将结果存储回堆栈中。它只在ST0ST1之间执行乘法操作,但是当它们的值为整数时,使用的密度为16位(计算2个字)。例如,执行FIMULWORD PTR [eax]通常用于使用16位整数执行浮点数乘法。 FIMUL指令使用栈操作数。

FMUL指令用于将浮点寄存器或内存中的浮点数乘以另一个浮点数,并将结果存储回寄存器中。FMUL指令支持多种操作数类型,包括寄存器、内存、以及立即值等。例如,将浮点寄存器ST(0)中的值乘以双精度浮点数x,并将结果存储回ST(0),可以使用以下指令:

FLD qword ptr [x]
FMUL ST(0), ST(0)

FMULP指令也是乘法指令,它将栈顶部的两个浮点数相乘,并将结果存储在次栈顶的浮点寄存器中。与FSUBP类似,它不需要第一个操作数。例如,将栈顶的两个单精度浮点数相乘,并将结果存储到内存z中,可以使用以下指令:

FMULP ST(1), ST(0)
FSTP dword ptr [z]

FIMUL指令用于将有符号整数乘以浮点寄存器中的另一个浮点数。与FISUB类似,它加载一个有符号整数并将其作为源操作数组合浮点寄存器中另一个浮点数进行乘法运算。例如,将浮点寄存器ST(0)中的值乘以16位有符号整数 y,并将结果存储回ST(0),可以使用以下指令:

FILD word ptr [y]
FMUL ST(0), ST(0)

接下来我们通过一个案例,并使用三种不同的浮点数乘法指令,分别演示四种不同的乘法计算方式,读者可自行编译学习;

  .386p
  .model flat,stdcall
  option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib

.data
  Array      QWORD 10.0,20.0,30.0,40.0,50.0
  IntQWORD   QWORD 20
  Result     QWORD ?
  
  szFmt BYTE 'ST寄存器: %f ',0dh,0ah,0 
.code
InitFLD PROC
  finit
  fld qword ptr ds:[Array]
  fld qword ptr ds:[Array + 8]
  fld qword ptr ds:[Array + 16]
  fld qword ptr ds:[Array + 24]
  fld qword ptr ds:[Array + 32]
  ret
InitFLD endp

  main PROC
    invoke InitFLD
    ; 第一种:无操作数乘法与除法
    fmul
    fmulp              ; st(0) = st(0) * st(1)
    fst qword ptr ds:[Result]
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    
    ; 第二种:两个浮点数寄存器之间的乘法
    invoke InitFLD
    fmul st(0),st(4)    ; st(0) = st(0) * st(4)
    fst qword ptr ds:[Result]
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]

    ; 第三种:寄存器与内存之间的乘法与除法
    invoke InitFLD
    fmul qword ptr ds:[Array + 8]     ; st(0) = st(0) * [Array + 8]
    fst qword ptr ds:[Result]
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    
    ; 第四种:与整数之间的乘法
    invoke InitFLD
    fimul dword ptr ds:[IntQWORD]     ; st(0) = st(0) * IntQWORD
    fst qword ptr ds:[Result]
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    
    int 3
  main ENDP
END main

9.6 FDIV/FDIVP/FIDIV

对于浮点数除法运算其调用原理与乘法运算完全一致,对于浮点数除指令同样包含有FDIV/FDIVP/FIDIV这三种类型,如下则是三种类型的说明:

  • FDIV指令:将堆栈上的ST1浮点数除以ST0浮点数,并将结果存储回ST1中。 FDIV指令使用栈操作数。
  • FDIVP指令:将堆栈上的ST1浮点数除以ST0浮点数,不同于FDIV,它还将ST0从堆栈中弹出。例如,执行FDIVP ST1, ST0将ST1除以ST0,将结果存储回ST1中,然后将ST0从堆栈中弹出。 FDIVP指令使用栈操作数。
  • FIDIV指令:将堆栈上的浮点数(或整数)ST0ST1浮点数乘除,并将结果存储回堆栈中。 FIDIV指令使用栈操作数。

FDIV指令用于将浮点寄存器或内存中的浮点数除以另一个浮点数,并将结果存储回寄存器中。FDIV指令也支持多种操作数类型。例如,将浮点寄存器ST(0)中的值除以双精度浮点数 x,并将结果存储回ST(0),可以使用以下指令:

FLD qword ptr [x]
FDIV ST(0), ST(0)

FDIVP指令也是除法指令,它将栈顶两个浮点数相除,将次栈顶的浮点数弹出并将结果存储回次栈顶中。与FSUBPFMULP指令类似,它不需要第一个操作数。例如,将栈顶的两个单精度浮点数相除,并将结果存储到内存z中,可以使用以下指令:

FDIVP ST(1), ST(0)
FSTP dword ptr [z]

FIDIV 指令用于将浮点寄存器中的另一个浮点数除以有符号整数,与FIMUL相似,它加载有符号整数并将其作为除数进行浮点数除法运算。例如,将浮点寄存器ST(0)中的值除以16位有符号整数 y ,并将结果存储回ST(0),可以使用以下指令:

FILD word ptr [y]
FDIV ST(0), ST(0)

接下来我们通过一个案例,并使用三种不同的浮点数乘法指令,分别演示四种不同的除法计算方式,读者可自行编译学习;

  .386p
  .model flat,stdcall
  option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib

.data
  Array      QWORD 10.0,20.0,30.0,40.0,50.0
  IntQWORD   QWORD 20
  Result     QWORD ?
  
  szFmt BYTE 'ST寄存器: %f ',0dh,0ah,0 
.code
InitFLD PROC
  finit
  fld qword ptr ds:[Array]
  fld qword ptr ds:[Array + 8]
  fld qword ptr ds:[Array + 16]
  fld qword ptr ds:[Array + 24]
  fld qword ptr ds:[Array + 32]
  ret
InitFLD endp

  main PROC
    invoke InitFLD
    ; 第一种:无操作数除法
    fdiv
    fdivp              ; st(0) = st(0) / st(1)
    fst qword ptr ds:[Result]
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    
    ; 第二种:两个浮点数寄存器之间的除法
    invoke InitFLD
    
    fdiv st(0),st(2)    ; st(0) = st(0) / st(2)
    fst qword ptr ds:[Result]
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]

    ; 第三种:寄存器与内存之间的乘法与除法
    invoke InitFLD
    
    fdiv qword ptr ds:[Array + 16]    ; st(0) = st(0) / [Array + 16]
    fst qword ptr ds:[Result]
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    
    ; 第四种:与整数之间的乘法与除法
    invoke InitFLD
    
    fidiv dword ptr ds:[IntQWORD]     ; st(0) = st(0) / IntQWORD
    fst qword ptr ds:[Result]
    invoke crt_printf,addr szFmt,qword ptr ds:[Result]
    int 3
  main ENDP
END main

9.7 FCOM/FCOMP/FCOMPP

浮点数比较指令包括FCOM/FCOMP/FCOMPP这三个指令都是比较ST(0)和源操作数,源操作数可以是内存操作数或FPU寄存器,FCOMFCOMP格式基本一致,唯一区别在于FCOMP在执行对比后还要从堆栈中弹出元素,而FCOMPFCOMPP也基本一致,最后都是要从堆栈中弹出元素。

FCOM 指令用于比较浮点数寄存器ST(0)和源操作数中的浮点数,并设置状态字以指示两个数的关系。源操作数可以是内存操作数或者FPU寄存器。例如,比较浮点数寄存器ST(0)和内存中的双精度浮点数x,可以使用以下指令:

FLD qword ptr [x]
FCOM ST(0)

FCOMP指令与FCOM指令类似,只是在执行比较后,除了设置状态字以外,还会将栈顶元素弹出。例如,比较浮点数寄存器ST(0)和浮点数寄存器ST(1),并将栈顶元素弹出,可以使用以下指令:

FCOM ST(1)
FCOMP

FCOMPP指令也是用于比较两个浮点数寄存器ST(0)ST(1)的大小,并将栈顶的两个元素弹出。与FCOMP指令类似,但是可以比较两个栈顶的数值。例如,比较浮点数寄存器ST(0)和ST(1),并将栈顶的两个元素弹出,可以使用以下指令:

FCOMPP

比较指令的重点就是比较条件码的状态,FPU中包括三个条件状态,分别是C3(零标志),C2(奇偶标志),C0(进位标志),我们可以使用FNSTSW指令将这些状态字送入AX寄存器中,然后通过SAHF指令把AH赋值到EFLAGS标志中,一旦标志状态被送入EFLAGS寄存器,那么就可以使用标准的标志位对跳转指令进行影响,例如以下C语言代码实现。

double x = 1.2; double y = 3.0; int n = 0;
if(x < y)
{
  n=1;
}

当此段代码使用汇编语言实现时,读者可写出如下所示的对等代码,其中当调用fcomp时自动完成比较并通过fnstsw ax的方式将状态值送入到AX寄存器中,然后再调用sahf将状态值送入到EFLAGS寄存器组,此时,我们就可以使用通用的跳转指令实现跳转了。

  .386p
  .model flat,stdcall
  option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib

.data
  x REAL8 1.2
  y REAL8 3.0
  n DWORD 0
.code
  main PROC
    fld x        ; st(0) = x
    fcomp y      ; cmp x,y ; pop x
    fnstsw ax    ; 取出状态值送入AX
    sahf         ; 将状态字送入EFLAGS
    jnb L1       ; x < y 小于
    mov n,1      ; 满足则将n置1

  L1: xor eax,eax  ; 否则清空寄存器
    int 3
  main ENDP
END main

对于上述中所示的案例来说,由于浮点数运算比整数运算在开销上会更大一些,因此Intel新版处理器新增加了FCOMI指令,专门用于比较两个浮点数的值,并自动设置零标志,基偶标志,和进位标志,唯一的缺点是其不支持内存操作数,但当读者需要使用是也是可以使用的,这段案例如下所示;

  .386p
  .model flat,stdcall
  option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib

.data
  x REAL8 1.2
  y REAL8 3.0
  n DWORD 0
.code
  main PROC
    fld y
    fld x
    fcomi st(0),st(1)
    jnb L1            ; st(0) not st(1) ?
    mov n,1
    
  L1: xor eax,eax
    int 3
  main ENDP
END main

对于浮点数的比较来说,例如比较X与Y是否相等,如果比较X==y?则可能会出现近似值的情况,导致无法计算出正确结果,正确的做法是取其差值的绝对值,并和用户自定义的小的正数相比较,小的正整数作为两个值相等时其差值的临界值。

  .386p
  .model flat,stdcall
  option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib

.data
  epsilon REAL8 1.0E-12
  var2    REAL8 0.0
  var3    REAL8 1.001E-13
.code
  main PROC
    fld epsilon
    fld var2
    fsub var3
    fabs
    fcomi st(0),st(1) ; cmp epsilon,var2
    ja skip
    xor ebx,ebx       ; 相等则清空ebx
  skip:
    int 3             ; 不相等则结束
  main ENDP
END main
...全文
298 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
第1章 计算机与C++编程简介 1.1 简介 1.2 什么是计算机 1.3 计算机组成 1.4 操作系统的变革 I.5 个人计算、分布式计算与客户/a匠务器计算 l. 6 机器语言、汇编语言和高级语言 1.7 C语言与C++的历史 1.8 C++标准库 1.9 Java、Internet与万维网 1.10 其他高级语言 1.11 结构化编程 1.12 典型C++环境基础 1.13 C++与本书的一般说明 1.14 C++编程简介 1.15 简单程序:打印一行文本 1.16 简单程序:两个整数相加 1.17 内存的概念 1.18 算术运算 1.19 判断:相等与关系运算符 1.20 新型头文件与名字空间 1.21 有关对象的思考 小结 术语 自测练习 自测练习答案 练习 第2章 控制结构 2.1 简介 2.2 算法 2.3 伪代码 2.4 控制结构 2.5 if选择结构 2.6 if/e1se选择结构 2.7 while重复结构 2.8 构造算法:实例研究1(计数器控制重复) 2.9 构造算法与自上而下逐步完善:实例研究2(标记控制重复) 2.10 构造算法与自上而下逐步完善:实例研究3(嵌套控制结构) 2.11 赋值运算符 2.12 自增和自减运算符 2.13 计数器控制循环的要点 2.14 for重复结构 2.15 for结构使用举例 2.16 switch多项选择结构 2.17 do/while重复结构 2.18 break和continue语句 2.19 逻辑运算符 2.20 混淆相等(.==)与赋值(=)运算符 2.21 结构化编程小结 2.22 有关对象的思考:确定问题中的对象 小结 术语 自测练习 自测练习答案 练习 第3章 函数 3.1 简介 3.2 C++程序组件 3.3 数学函数库 3.4 函数 3.5 函数定义 3.6 函数原型 3.7 头文件 3.8 随机数产生器 3.9 案例:机会游戏与enum简介 3.10 存储类 3.11 作用域规则 3.12 递归 3.13 使用递归举例:Fibonacci数列 3.14 递归与迭代 3.15 带空参数表的函数 3.16 内联函数 3.17 引用与引用参数 3.18 默认参数 3.19 一元作用域运算符 3.20 函数重载 3.21 函数模板 3.22 有关对象的思考:确定对象属性 小结 术语 自测练习 自测练习答案 练习 第4章 数组 4.1 简介 4.2 数组 4.3 声明数组 4.4 使用数组的举例 4.5 将数组传递给函数 4.6 排序数组 4.7 实例研究:用数组计算平均值、中数和模 4.8 查找数组:线性查找与折半查找 4.9 多下标数组 4.10 有关对象的思考:确定类的行为 小结 术语 自测练习 自测练习答案 练习 递归练习 第5章 指针与字符串 5.1 简介 5.2 指针变量的声明与初始化 5.3 指针运算符 5.4 按引用调用函数 5.5 指针与常量限定符 5.6 按引用调用的冒泡排序 5.7 指针表达式与指针算法 5.8 指针与数组的关系 5.9 指针数组 5.10 实例研究:洗牌与发牌 5.11 函数指针 5.12 字符与字符串处理简介 5.12.1 字符与字符串基础 5.12.2 字符串处理库的字符串操作函数 5.13 有关对象的思考:对象间的交互 小结 术语 自测练习 自测练习答案 练习 特殊小节:建立自己的计算机 更多的指针练习 字符串操作练习 特殊小节:高级字符串操作练习 复杂字符串操作练习 第6章 类与数据抽象(一) 6.1 简介 6.2 结构定义 6.3 访问结构成员 6.4 用struct实现用户自定义类型Time 6.5 用类实现Time抽象数据类型 6.6 类范围与访问类成员 6.7 接口与实现方法的分离 6.8 控制对成员的访问 6.9 访问函数与工具函数 6.10 初始化类对象:构造函数 6.11 在构造函数中使用默认参数 6.12 使用析构函数 6.13 何时调用构造函数与析构函数 6.14 使用数据成员和成员函数 6.15 微妙的陷阱:返回对Private数据成员的引用 6.16 通过默认的成员复制进行赋值 6.17 软件复用性 6.18 有关对象的思考:编写电梯模拟程序的类 小结 术语 自测练习 自测练习答案 练习 第7章 类与数据抽象(二) 7. 1 简介 7.2 const(常量)对象与const成员函数 7.3 复合:把对象作为类成员 7.4 友元函数与友元类 7.5 使用this指针 7.6 动态内存分配与new和delete运算符 7.7 static类成员 7.8 数据抽象与信息隐藏 7.8.1 范例:数组抽象数据类型 7.8.2 范例:字符串抽象数据类型 7.8.3 范例:队列抽象数据类型 7.9 容器类与迭代 7.10 代理类 7.11 有关对象的思考:在电梯模拟程序中使用复合和动态对象管理 小结 术语 自测练习 自测练习答案 练习 第8章 运算符重载 8.1 简介 8.2 运算符重载的基础 8.3 运算符重载的限制 8.4 用作类成员与友元函数的运算符函数 8.5 重载流插入与流读取运算符 8.6 重载一元运算符 8.7 重载二元运算符 8.8 实例研究:Array类 8.9 类型之间的转换 8.10 实例研究:String类 8.11 重载十十与—— 8.12 实例研究:Date类 小结 术语 自测练习 自测练习答案 练习 第9章 继承 9.1 简介 9.2 继承:基类和派生类 9.3 Protected成员 9.4 把基类指针强制转换为派生类指针 9.5 使用成员函数 9.6 在派生类中重定义基类成员 9.7 Public、Protected和Private继承 9.8 直接基类和间接基类 9.9 在派生类中使用构造函数和析构函数 9.10 将派生类对象隐式转换为基类对象 9.11 关于继承的软件工程 9.12 复合与继承的比较 9.13 对象的“使用”关系和“知道”关系 9.14 实例研究:类Point、CircIe和Cylinder 9.15 多重继承 小结 术语 自测练习 自测练习答案 练习 第10章 虚函数和多态性 10.1 简介 10.2 类型域和switch语句 10.3 虚函数 10.4 抽象基类和具体类 10.5 多态性 10.6 实例研究:利用多态性的工资单系统 10.7 新类和动态关联 10.8 虚析构函数 10.9 实例研究:继承接口和实现 10.10 多态、虚函数和动态关联 小结 术语 自测练习 自测练习答案 练习 第11章 C++输入/输出流 11.1 简介 11.2 流 11.2.1 iosbeam类库的头文件 11.2.2 输入/输出流类和对象 11.3 输出流 11.3.1 流插入运算符 11.3. 2 连续使用流插入/流读取运算符 11.3.3 输出char类型的变量 11.3.4 用成员函数put输出字符和put函数的连续调用 11.4 输入流 11.4.1 流读取运算符 11.4.2 成员函数get和getline 11.4.3 istream类中的其他成员函数(Peek、Putback和ignore) 11.4.4 类型安全的I/0 11.5 成员函数read、gcount和write的无格式输人/输出 11.6 流操纵算子 11.6.1 整数流的基数:流操纵算子dec、oct、hex和setbase 11.6.2 设置浮点数精度(Precision、setprecision) 11.6.3 设置域宽(setw、width) 11.6.4 用户自定义的流操纵算子 11.7 流格式状态 11.7.1 格式状态标志 11.7.2 尾数零和十进制小数点(ios:showpoint) 11.7.3 对齐(ios::left、ios::right、ios::internal) 11.7.4 设置填充字符(fill、setfill) 11.7.5 整数流的基数:(ios::dec、ios::oct、ios::hex、ios::showbase) 11. 7.6 浮点数和科学记数法(ios::scientific、ios::fixed) 11.7.7 大/小写控制(ios:uppercase) 11.7.8 设置及清除格式标志(flags、setiosflags、resetiosflags) 11.8 流错误状态 11.9 把输出流连到输入流上 小结 术语 自测练习 自测练习答案 练习 第12章 模板 12.1 简介 12.2 函数模板 12.3 重载模板函数 12.4 类模板 12.5 类模板与非类型参数 12.6 模板与继承 12.7 模板与友元 12.8 模板与static成员 小结 术语 自测练习 自测练习答案 练习 第13章 异常处理 13.1 简介 13.2 何时使用异常处理 13.3 其他错误处理方法 13.4 C十十异常处理基础:try、throw、catch 13.5 简单异常处理例子:除数为o 13.6 抛出异常 13.7 捕获异常 13.8 再抛出异常 13.9 异常指定 13.10 处理意外异常 13.11 堆栈解退 13.12 构造函数、析构函数与异常处理 13.13 异常与继承 13.14 处理new故障 13.15 auto_ptr类与动态内存分配 13.16 标准库异常层次 小结 术语 自测练习 自测练习答案 练习 第14章 文件处理 14.1 简介 14.2 数据的层次 14.3 文件和流 14.4 建立顺序访问文件 14.5 读取顺序访问文件中的数据 14.6 更新顺序访问文件 14.7 随机访问文件 14.8 建立随机访问文件 14.9 向随机访问文件中随机地写入数据 14.10 从随机访问文件中顺序地读取数据 14.11 实例研究:事务处理程序 14.12 对象的输入/输出 小结 术语 自测练习 自测练习答案 练习 第15章 数据结构 15.1 简介 15.2 自引用类 15.3 动态内存分配 15.4 链表 15.5 堆栈 15.6 队列 15.7 树 小结 术语 自测练习 自测练习答案 练习 特殊小节:建立自己的编译器 第16章 位、字符、字符串和结构 16.1 简介 16.2 结构的定义 16.3 结构的初始化 16.4 函数和结构 16.5 类型定义:typedef 16. 6 范例:高效的洗牌和发牌模拟程序 16.7 位运算符 16.8 位段 16.9 字符处理库 16.10 字符串转换函数 16.11 字符串处理库中的查找函数 16.12 字符串处理库中的内存函数 16.13 字符串处理库中的其他函数 小结 术语 自测练习 自测练习答案 练习 第17章 预处理器 17.1 简介 17.2 预处理指令#include 17.3 预处理指令#define:符号常量 17.4 预处理指令#define:宏 17.5 条件编译 17.6 预处理指令#error和#pragma 17.7 运算符#和## 17.8 行号 17.9 预定义的符号常量 17.10 断言(宏assert) 小结 术语 自测练习 自测练习答案 练习 第18章 C语言遗留代码问题 18.1 简介 18.2 UNIX和DOS系统中的输入/输出重定向 18.3 变长参数表 18.4 使用命令行参数 18.5 对编译多个源文件程序的说明 18. 6 用edt和atexit终止程序的执行 18.7 volatile类型限定符 18.8 整数和浮点数常量的后缀 18.9 信号处理 18.10 动态内存分配:函数calloc和realloc 18.11 无条件转移:goto语句 18.12 联合体 18.13 连接指定 小结 术语 自测练习 自测练习答案 练习 第19章 string类与字符串流处理 19.1 简介 19.2 string的赋值与连接 19.3 比较string 19.4 子串 19.5 交换string 19.6 string的特性 19.7 寻找string中的字符 19.8 替换string中的字符 19.9 在string中插入字符 19.10 转换成C语言式char 字符串 19.11 迭代器 19.12 字符串流处理 小结 术语 自测练习 自测练习答案 练习 第20章 标准模板库(STL) 20.1 标准模板库(STL)简介 20.1.1 容器简介 20.1.2 迭代器简介 20.1.3 算法简介 20.2 顺序容器 20.2.1 vector顺序容器 20.2.2 1ist顺序容器 20.2.3 deque顺序容器 20.3 关联容器 20.3.1 multiset关联容器 20. 3.2 set关联容器 20.3.3 mdtimap关联容器 20.3.4 map关联容器 20.4 容器适配器 20.4.1 stack适配器 20.4.2 queue适配器 20.4.3 Priority_queue适配器 20.5 算法 20.5.1 fill、fill_n、generate与generate_n 20.5.2 equal、mismatch和1exicographical_compare 20.5.3 remove、remove_if、 remove_copy和remove_copy_if 20.5.4 replace、replace_if、replace_copy和replace_copy_if 20.5.5 数学算法 20.5.6 基本查找与排序算法 20.5.7 swap、iter_swap和swap_ranges 20.5.8 copy—backward、 merge、 unique和reverse 20.5.9 inplace_merge、 unique—copy和reverse—copy 20.5.10 集合操作 20.5.11 1ower—bound、 upper—bound和equal_range 20.5.12 堆排序 20.5.13 min和max 20.5.14 本章未介绍的算法 20.6 bitset类 20.7 函数对象 小结 术语 自测练习 自测练习答案 练习 Internet和World Wide Web中的STL资源 STL文献 第21章 ANSI/ISO C++标准语言补充 21.1 简介 21.2 bool数据类型 21.3 static—cast运算符 21.4 const—cast运算符 21.5 reinterpret—cast运算符 21.6 名字空间 21.7 运行时类型信息(RTTI) 21.8 运算符关键字 21.9 explicit构造函数 21.10 mutable类成员 21.11 类成员指针(.和—>) 21.12 多重继承与virtual基类 21.13 结束语 小结 术语 自测练习 自测练习答案 练习 附录A 运算符的优先级与结台律 附录B ASCII字符集 附录C 数值系统 附录D 有关C++的Internet与Web资源 参考文献 【媒体评论】
第1章 计算机与C++编程简介 1.1 简介 1.2 什么是计算机 1.3 计算机组成 1.4 操作系统的变革 I.5 个人计算、分布式计算与客户/a匠务器计算 l. 6 机器语言、汇编语言和高级语言 1.7 C语言与C++的历史 1.8 C++标准库 1.9 Java、Internet与万维网 1.10 其他高级语言 1.11 结构化编程 1.12 典型C++环境基础 1.13 C++与本书的一般说明 1.14 C++编程简介 1.15 简单程序:打印一行文本 1.16 简单程序:两个整数相加 1.17 内存的概念 1.18 算术运算 1.19 判断:相等与关系运算符 1.20 新型头文件与名字空间 1.21 有关对象的思考 小结 术语 自测练习 自测练习答案 练习 第2章 控制结构 2.1 简介 2.2 算法 2.3 伪代码 2.4 控制结构 2.5 if选择结构 2.6 if/e1se选择结构 2.7 while重复结构 2.8 构造算法:实例研究1(计数器控制重复) 2.9 构造算法与自上而下逐步完善:实例研究2(标记控制重复) 2.10 构造算法与自上而下逐步完善:实例研究3(嵌套控制结构) 2.11 赋值运算符 2.12 自增和自减运算符 2.13 计数器控制循环的要点 2.14 for重复结构 2.15 for结构使用举例 2.16 switch多项选择结构 2.17 do/while重复结构 2.18 break和continue语句 2.19 逻辑运算符 2.20 混淆相等(.==)与赋值(=)运算符 2.21 结构化编程小结 2.22 有关对象的思考:确定问题中的对象 小结 术语 自测练习 自测练习答案 练习 第3章 函数 3.1 简介 3.2 C++程序组件 3.3 数学函数库 3.4 函数 3.5 函数定义 3.6 函数原型 3.7 头文件 3.8 随机数产生器 3.9 案例:机会游戏与enum简介 3.10 存储类 3.11 作用域规则 3.12 递归 3.13 使用递归举例:Fibonacci数列 3.14 递归与迭代 3.15 带空参数表的函数 3.16 内联函数 3.17 引用与引用参数 3.18 默认参数 3.19 一元作用域运算符 3.20 函数重载 3.21 函数模板 3.22 有关对象的思考:确定对象属性 小结 术语 自测练习 自测练习答案 练习 第4章 数组 4.1 简介 4.2 数组 4.3 声明数组 4.4 使用数组的举例 4.5 将数组传递给函数 4.6 排序数组 4.7 实例研究:用数组计算平均值、中数和模 4.8 查找数组:线性查找与折半查找 4.9 多下标数组 4.10 有关对象的思考:确定类的行为 小结 术语 自测练习 自测练习答案 练习 递归练习 第5章 指针与字符串 5.1 简介 5.2 指针变量的声明与初始化 5.3 指针运算符 5.4 按引用调用函数 5.5 指针与常量限定符 5.6 按引用调用的冒泡排序 5.7 指针表达式与指针算法 5.8 指针与数组的关系 5.9 指针数组 5.10 实例研究:洗牌与发牌 5.11 函数指针 5.12 字符与字符串处理简介 5.12.1 字符与字符串基础 5.12.2 字符串处理库的字符串操作函数 5.13 有关对象的思考:对象间的交互 小结 术语 自测练习 自测练习答案 练习 特殊小节:建立自己的计算机 更多的指针练习 字符串操作练习 特殊小节:高级字符串操作练习 复杂字符串操作练习 第6章 类与数据抽象(一) 6.1 简介 6.2 结构定义 6.3 访问结构成员 6.4 用struct实现用户自定义类型Time 6.5 用类实现Time抽象数据类型 6.6 类范围与访问类成员 6.7 接口与实现方法的分离 6.8 控制对成员的访问 6.9 访问函数与工具函数 6.10 初始化类对象:构造函数 6.11 在构造函数中使用默认参数 6.12 使用析构函数 6.13 何时调用构造函数与析构函数 6.14 使用数据成员和成员函数 6.15 微妙的陷阱:返回对Private数据成员的引用 6.16 通过默认的成员复制进行赋值 6.17 软件复用性 6.18 有关对象的思考:编写电梯模拟程序的类 小结 术语 自测练习 自测练习答案 练习 第7章 类与数据抽象(二) 7. 1 简介 7.2 const(常量)对象与const成员函数 7.3 复合:把对象作为类成员 7.4 友元函数与友元类 7.5 使用this指针 7.6 动态内存分配与new和delete运算符 7.7 static类成员 7.8 数据抽象与信息隐藏 7.8.1 范例:数组抽象数据类型 7.8.2 范例:字符串抽象数据类型 7.8.3 范例:队列抽象数据类型 7.9 容器类与迭代 7.10 代理类 7.11 有关对象的思考:在电梯模拟程序中使用复合和动态对象管理 小结 术语 自测练习 自测练习答案 练习 第8章 运算符重载 8.1 简介 8.2 运算符重载的基础 8.3 运算符重载的限制 8.4 用作类成员与友元函数的运算符函数 8.5 重载流插入与流读取运算符 8.6 重载一元运算符 8.7 重载二元运算符 8.8 实例研究:Array类 8.9 类型之间的转换 8.10 实例研究:String类 8.11 重载十十与—— 8.12 实例研究:Date类 小结 术语 自测练习 自测练习答案 练习 第9章 继承 9.1 简介 9.2 继承:基类和派生类 9.3 Protected成员 9.4 把基类指针强制转换为派生类指针 9.5 使用成员函数 9.6 在派生类中重定义基类成员 9.7 Public、Protected和Private继承 9.8 直接基类和间接基类 9.9 在派生类中使用构造函数和析构函数 9.10 将派生类对象隐式转换为基类对象 9.11 关于继承的软件工程 9.12 复合与继承的比较 9.13 对象的“使用”关系和“知道”关系 9.14 实例研究:类Point、CircIe和Cylinder 9.15 多重继承 小结 术语 自测练习 自测练习答案 练习 第10章 虚函数和多态性 10.1 简介 10.2 类型域和switch语句 10.3 虚函数 10.4 抽象基类和具体类 10.5 多态性 10.6 实例研究:利用多态性的工资单系统 10.7 新类和动态关联 10.8 虚析构函数 10.9 实例研究:继承接口和实现 10.10 多态、虚函数和动态关联 小结 术语 自测练习 自测练习答案 练习 第11章 C++输入/输出流 11.1 简介 11.2 流 11.2.1 iosbeam类库的头文件 11.2.2 输入/输出流类和对象 11.3 输出流 11.3.1 流插入运算符 11.3. 2 连续使用流插入/流读取运算符 11.3.3 输出char类型的变量 11.3.4 用成员函数put输出字符和put函数的连续调用 11.4 输入流 11.4.1 流读取运算符 11.4.2 成员函数get和getline 11.4.3 istream类中的其他成员函数(Peek、Putback和ignore) 11.4.4 类型安全的I/0 11.5 成员函数read、gcount和write的无格式输人/输出 11.6 流操纵算子 11.6.1 整数流的基数:流操纵算子dec、oct、hex和setbase 11.6.2 设置浮点数精度(Precision、setprecision) 11.6.3 设置域宽(setw、width) 11.6.4 用户自定义的流操纵算子 11.7 流格式状态 11.7.1 格式状态标志 11.7.2 尾数零和十进制小数点(ios:showpoint) 11.7.3 对齐(ios::left、ios::right、ios::internal) 11.7.4 设置填充字符(fill、setfill) 11.7.5 整数流的基数:(ios::dec、ios::oct、ios::hex、ios::showbase) 11. 7.6 浮点数和科学记数法(ios::scientific、ios::fixed) 11.7.7 大/小写控制(ios:uppercase) 11.7.8 设置及清除格式标志(flags、setiosflags、resetiosflags) 11.8 流错误状态 11.9 把输出流连到输入流上 小结 术语 自测练习 自测练习答案 练习 第12章 模板 12.1 简介 12.2 函数模板 12.3 重载模板函数 12.4 类模板 12.5 类模板与非类型参数 12.6 模板与继承 12.7 模板与友元 12.8 模板与static成员 小结 术语 自测练习 自测练习答案 练习 第13章 异常处理 13.1 简介 13.2 何时使用异常处理 13.3 其他错误处理方法 13.4 C十十异常处理基础:try、throw、catch 13.5 简单异常处理例子:除数为o 13.6 抛出异常 13.7 捕获异常 13.8 再抛出异常 13.9 异常指定 13.10 处理意外异常 13.11 堆栈解退 13.12 构造函数、析构函数与异常处理 13.13 异常与继承 13.14 处理new故障 13.15 auto_ptr类与动态内存分配 13.16 标准库异常层次 小结 术语 自测练习 自测练习答案 练习 第14章 文件处理 14.1 简介 14.2 数据的层次 14.3 文件和流 14.4 建立顺序访问文件 14.5 读取顺序访问文件中的数据 14.6 更新顺序访问文件 14.7 随机访问文件 14.8 建立随机访问文件 14.9 向随机访问文件中随机地写入数据 14.10 从随机访问文件中顺序地读取数据 14.11 实例研究:事务处理程序 14.12 对象的输入/输出 小结 术语 自测练习 自测练习答案 练习 第15章 数据结构 15.1 简介 15.2 自引用类 15.3 动态内存分配 15.4 链表 15.5 堆栈 15.6 队列 15.7 树 小结 术语 自测练习 自测练习答案 练习 特殊小节:建立自己的编译器 第16章 位、字符、字符串和结构 16.1 简介 16.2 结构的定义 16.3 结构的初始化 16.4 函数和结构 16.5 类型定义:typedef 16. 6 范例:高效的洗牌和发牌模拟程序 16.7 位运算符 16.8 位段 16.9 字符处理库 16.10 字符串转换函数 16.11 字符串处理库中的查找函数 16.12 字符串处理库中的内存函数 16.13 字符串处理库中的其他函数 小结 术语 自测练习 自测练习答案 练习 第17章 预处理器 17.1 简介 17.2 预处理指令#include 17.3 预处理指令#define:符号常量 17.4 预处理指令#define:宏 17.5 条件编译 17.6 预处理指令#error和#pragma 17.7 运算符#和## 17.8 行号 17.9 预定义的符号常量 17.10 断言(宏assert) 小结 术语 自测练习 自测练习答案 练习 第18章 C语言遗留代码问题 18.1 简介 18.2 UNIX和DOS系统中的输入/输出重定向 18.3 变长参数表 18.4 使用命令行参数 18.5 对编译多个源文件程序的说明 18. 6 用edt和atexit终止程序的执行 18.7 volatile类型限定符 18.8 整数和浮点数常量的后缀 18.9 信号处理 18.10 动态内存分配:函数calloc和realloc 18.11 无条件转移:goto语句 18.12 联合体 18.13 连接指定 小结 术语 自测练习 自测练习答案 练习 第19章 string类与字符串流处理 19.1 简介 19.2 string的赋值与连接 19.3 比较string 19.4 子串 19.5 交换string 19.6 string的特性 19.7 寻找string中的字符 19.8 替换string中的字符 19.9 在string中插入字符 19.10 转换成C语言式char 字符串 19.11 迭代器 19.12 字符串流处理 小结 术语 自测练习 自测练习答案 练习 第20章 标准模板库(STL) 20.1 标准模板库(STL)简介 20.1.1 容器简介 20.1.2 迭代器简介 20.1.3 算法简介 20.2 顺序容器 20.2.1 vector顺序容器 20.2.2 1ist顺序容器 20.2.3 deque顺序容器 20.3 关联容器 20.3.1 multiset关联容器 20. 3.2 set关联容器 20.3.3 mdtimap关联容器 20.3.4 map关联容器 20.4 容器适配器 20.4.1 stack适配器 20.4.2 queue适配器 20.4.3 Priority_queue适配器 20.5 算法 20.5.1 fill、fill_n、generate与generate_n 20.5.2 equal、mismatch和1exicographical_compare 20.5.3 remove、remove_if、 remove_copy和remove_copy_if 20.5.4 replace、replace_if、replace_copy和replace_copy_if 20.5.5 数学算法 20.5.6 基本查找与排序算法 20.5.7 swap、iter_swap和swap_ranges 20.5.8 copy—backward、 merge、 unique和reverse 20.5.9 inplace_merge、 unique—copy和reverse—copy 20.5.10 集合操作 20.5.11 1ower—bound、 upper—bound和equal_range 20.5.12 堆排序 20.5.13 min和max 20.5.14 本章未介绍的算法 20.6 bitset类 20.7 函数对象 小结 术语 自测练习 自测练习答案 练习 Internet和World Wide Web中的STL资源 STL文献 第21章 ANSI/ISO C++标准语言补充 21.1 简介 21.2 bool数据类型 21.3 static—cast运算符 21.4 const—cast运算符 21.5 reinterpret—cast运算符 21.6 名字空间 21.7 运行时类型信息(RTTI) 21.8 运算符关键字 21.9 explicit构造函数 21.10 mutable类成员 21.11 类成员指针(.和—>) 21.12 多重继承与virtual基类 21.13 结束语 小结 术语 自测练习 自测练习答案 练习 附录A 运算符的优先级与结台律 附录B ASCII字符集 附录C 数值系统 附录D 有关C++的Internet与Web资源 参考文献 【媒体评论】
Complete Digital Design - A Comprehensive Guide to Digital Electronics and Computer System Architecture PART 1 Digital Fundamentals Chapter 1 Digital Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 1.1 Boolean Logic / 3 1.2 Boolean Manipulation / 7 1.3 The Karnaugh map / 8 1.4 Binary and Hexadecimal Numbering / 10 1.5 Binary Addition / 14 1.6 Subtraction and Negative Numbers / 15 1.7 Multiplication and Division / 17 1.8 Flip-Flops and Latches / 18 1.9 Synchronous Logic / 21 1.10 Synchronous Timing Analysis / 23 1.11 Clock Skew / 25 1.12 Clock Jitter / 27 1.13 Derived Logical Building Blocks / 28 Chapter 2 Integrated Circuits and the 7400 Logic Families. . . . . . . . . . . . . . . . . . . . .33 2.1 The Integrated Circuit / 33 2.2 IC Packaging / 38 2.3 The 7400-Series Discrete Logic Family / 41 2.4 Applying the 7400 Family to Logic Design / 43 2.5 Synchronous Logic Design with the 7400 Family / 45 2.6 Common Variants of the 7400 Family / 50 2.7 Interpreting a Digital IC Data Sheet / 51 Chapter 3 Basic Computer Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .55 3.1 The Digital Computer / 56 3.2 Microprocessor Internals / 58 3.3 Subroutines and the Stack / 60 3.4 Reset and Interrupts / 62 3.5 Implementation of an Eight-Bit Computer / 63 3.6 Address Banking / 67 3.7 Direct Memory Access / 68 3.8 Extending the Microprocessor Bus / 70 3.9 Assembly Language and Addressing Modes / 72 Chapter 4 Memory. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .77 4.1 Memory Classifications / 77 4.2 EPROM / 79 4.3 Flash Memory / 81 4.4 EEPROM / 85 4.5 Asynchronous SRAM / 86 4.6 Asynchronous DRAM / 88 4.7 Multiport Memory / 92 4.8 The FIFO / 94 Chapter 5 Serial Communications. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .97 5.1 Serial vs. Parallel Communication / 98 5.2 The UART / 99 5.3 ASCII Data Representation / 102 5.4 RS-232 / 102 5.5 RS-422 / 107 5.6 Modems and Baud Rate / 108 5.7 Network Topologies / 109 5.8 Network Data Formats / 110 5.9 RS-485 / 112 5.10 A Simple RS-485 Network / 114 5.11 Interchip Serial Communications / 117 Chapter 6 Instructive Microprocessors and Microcomputer Elements . . . . . . . . . .121 6.1 Evolution / 121 6.2 Motorola 6800 Eight-bit Microprocessor Family / 122 6.3 Intel 8051 Microcontroller Family / 125 6.4 Microchip PIC® Microcontroller Family / 131 6.5 Intel 8086 16-Bit Microprocessor Family / 134 6.6 Motorola 68000 16/32-Bit Microprocessor Family / 139 PART 2 Advanced Digital Systems Chapter 7 Advanced Microprocessor Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . .145 7.1 RISC and CISC / 145 7.2 Cache Structures / 149 7.3 Caches in Practice / 154 7.4 Virtual Memory and the MMU / 158 7.5 Superpipelined and Superscalar Architectures / 161 7.6 Floating-Point Arithmetic / 165 7.7 Digital Signal Processors / 167 7.8 Performance Metrics / 169 Chapter 8 High-Performance Memory Technologies. . . . . . . . . . . . . . . . . . . . . . . . .173 8.1 Synchronous DRAM / 173 8.2 Double Data Rate SDRAM / 179 8.3 Synchronous SRAM / 182 8.4 DDR and QDR SRAM / 185 8.5 Content Addressable Memory / 188 Chapter 9 Networking. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .193 9.1 Protocol Layers One and Two / 193 9.2 Protocol Layers Three and Four / 194 9.3 Physical Media / 197 9.4 Channel Coding / 198 9.5 8B10B Coding / 203 9.6 Error Detection / 207 9.7 Checksum / 208 9.8 Cyclic Redundancy Check / 209 9.9 Ethernet / 215 Chapter 10 Logic Design and Finite State Machines . . . . . . . . . . . . . . . . . . . . . . . . .221 10.1 Hardware Description Languages / 221 10.2 CPU Support Logic / 227 10.3 Clock Domain Crossing / 233 10.4 Finite State Machines / 237 10.5 FSM Bus Control / 239 10.6 FSM Optimization / 243 10.7 Pipelining / 245 Chapter 11 Programmable Logic Devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .249 11.1 Custom and Programmable Logic / 249 11.2 GALs and PALs / 252 11.3 CPLDs / 255 11.4 FPGAs / 257 PART 3 Analog Basics for Digital Systems Chapter 12 Electrical Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .267 12.1 Basic Circuits / 267 12.2 Loop and Node Analysis / 268 12.3 Resistance Combination / 271 12.4 Capacitors / 272 12.5 Capacitors as AC Elements / 274 12.6 Inductors / 276 12.7 Nonideal RLC Models / 276 12.8 Frequency Domain Analysis / 279 12.9 Lowpass and Highpass Filters / 283 12.10 Transformers / 288 Chapter 13 Diodes and Transistors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .293 13.1 Diodes / 293 13.2 Power Circuits with Diodes / 296 13.3 Diodes in Digital Applications / 298 13.4 Bipolar Junction Transistors / 300 13.5 Digital Amplification with the BJT / 301 13.6 Logic Functions with the BJT / 304 13.7 Field-Effect Transistors / 306 13.8 Power FETs and JFETs / 309 Chapter 14 Operational Amplifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .311 14.1 The Ideal Op-amp / 311 14.2 Characteristics of Real Op-amps / 316 14.3 Bandwidth Limitations / 324 14.4 Input Resistance / 325 14.5 Summation Amplifier Circuits / 328 14.6 Active Filters / 331 14.7 Comparators and Hysteresis / 333 Chapter 15 Analog Interfaces for Digital Systems . . . . . . . . . . . . . . . . . . . . . . . . . . .339 15.1 Conversion between Analog and Digital Domains / 339 15.2 Sampling Rate and Aliasing / 341 15.3 ADC Circuits / 345 15.4 DAC Circuits / 348 15.5 Filters in Data Conversion Systems / 350 PART 4 Digital System Design in Practice Chapter 16 Clock Distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .355 16.1 Crystal Oscillators and Ceramic Resonators / 355 16.2 Low-Skew Clock Buffers / 357 16.3 Zero-Delay Buffers: The PLL / 360 16.4 Frequency Synthesis / 364 16.5 Delay-Locked Loops / 366 16.6 Source-Synchronous Clocking / 367 Chapter 17 Voltage Regulation and Power Distribution . . . . . . . . . . . . . . . . . . . . . .371 17.1 Voltage Regulation Basics / 372 17.2 Thermal Analysis / 374 17.3 Zener Diodes and Shunt Regulators / 376 17.4 Transistors and Discrete Series Regulators / 379 17.5 Linear Regulators / 382 17.6 Switching Regulators / 386 17.7 Power Distribution / 389 17.8 Electrical Integrity / 392 Chapter 18 Signal Integrity. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .397 18.1 Transmission Lines / 398 18.2 Termination / 403 18.3 Crosstalk / 408 18.4 Electromagnetic Interference / 410 18.5 Grounding and Electromagnetic Compatibility / 413 18.6 Electrostatic Discharge / 415 Chapter 19 Designing for Success . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .419 19.1 Practical Technologies / 420 19.2 Printed Circuit Boards / 422 19.3 Manually Wired Circuits / 425 19.4 Microprocessor Reset / 428 19.5 Design for Debug / 429 19.6 Boundary Scan / 431 19.7 Diagnostic Software / 433 19.8 Schematic Capture and Spice / 436 19.9 Test Equipment / 440 Appendix A Further Education. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .443 Index 445

5,123

社区成员

发帖
与我相关
我的任务
社区描述
微软技术社区为中国的开发者们提供一个技术干货传播平台,传递微软全球的技术和产品最新动态,分享各大技术方向的学习资源,同时也涵盖针对不同行业和场景的实践案例,希望可以全方位地帮助你获取更多知识和技能。
windowsmicrosoft 企业社区
社区管理员
  • 山月照空舟
  • 郑子铭
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

微软技术社区为中国的开发者们提供一个技术干货传播平台,传递微软全球的技术和产品最新动态,分享各大技术方向的学习资源,同时也涵盖针对不同行业和场景的实践案例,希望可以全方位地帮助你获取更多知识和技能。

予力众生,成就不凡!微软致力于用技术改变世界,助力企业实现数字化转型。

试试用AI创作助手写篇文章吧