1. 结构体

结构是给予逻辑相关的变量组的模板或模式。 结构中的变量称为字段。 程序语句可以作为单个实体访问结构,也可以访问单个字段。 结构通常包含不同类型的字段。 联合还将多个标识符组合在一起,但标识符与内存中的相同区域重叠。

  • COORD 结构体
    COORD 结构在Windows API中定义屏幕的坐标X和Y,字段X的偏移为0,字段Y的偏移为2.
COORD STRUCTX WORD ? ; offset 00Y WORD ? ; offset 02
COORD ENDS
1). 定义结构体

定义结构体使用STRUCTENDS, 结构体内部,使用相同的语法定义变量。

name STRUCTfield-declarations
name ENDS
  • 字段初始化
    当结构字段具有初始值设定项时,将在创建结构变量时分配值。字段初始化的类型如下:
    I. Undefined: 使用?标识未定义
    II. String literals: 用引号括起来的字符串
    III. Integers: 整数常量或整数表达式
    IV. Arrays: DUP初始化的数组

示例:

Employee STRUCTIdNum BYTE "000000000"LastName BYTE 30 DUP(0)Years WORD 0SalaryHistory DWORD 0,0,0,0
Employee ENDS

内存占用布局:

structure’s memory layout.png

  • 对齐结构体字段
    为获得最佳内存I / O性能,结构成员应与匹配其数据类型的地址对齐。 否则,CPU将需要更多时间来访问成员。 例如,双字成员应在双字边界上对齐。ALIGN datatype
Alignment of Structure Members.png

2). 定义结构体变量

可以声明结构变量,并可选择使用特定值进行初始化。

identifier structureType < initializer-list >

示例:

.data
point1 COORD <5,10>     ; X = 5, Y = 10
point2 COORD <20>       ; X = 20, Y = ?
point3 COORD <>         ; X = ?, Y = ?
worker Employee <>      ; (default initializers)person1 Employee <"555223333">      ; 初始化IdNum
person2 Employee {"555223333"}      ; 与上一行作用相同
person3 Employee <,"dJones">        ; 初始化LastName
person4 Employee <,,,2 DUP(20000)>  ; 初始化SalaryHistory
  • 结构体数组
    使用DUP操作指令创建一个结构体数组。
NumPoints = 3
AllPoints COORD NumPoints DUP(<0,0>)
  • 对齐结构体变量
    为获得最佳处理器性能,请将内存边界上的结构变量与最大结构成员对齐。
data
ALIGN DWORD
person Employee <>
3). 引用结构体变量

可以使用TYPE和SIZEOF运算符来引用结构变量和结构名称.

  • 获取所占字节数
TYPE Employee   ; 60
SIZEOF Employee ; 60
SIZEOF worker   ; 60
  • 引用成员
    对命名结构成员的引用需要结构变量作为限定符。
TYPE Employee.SalaryHistory     ; 4
LENGTHOF Employee.SalaryHistory ; 4
SIZEOF Employee.SalaryHistory   ; 16
TYPE Employee.Years             ; 2
  • 使用OFFSET操作
mov edx,OFFSET worker.LastName
  • 间接索引操作数
    间接操作数允许使用寄存器(例如ESI)来寻址结构成员。 间接寻址提供了灵活性,特别是在将结构地址传递给过程或使用结构数组时。
mov esi,OFFSET worker
mov ax,(Employee PTR [esi]).Years
  • 索引操作数
    我们可以使用索引操作数来访问结构体数组。
.datadepartment Employee 5 DUP(<>)
.codemov esi,TYPE Employee       ; index = 1mov department[esi].Years, 4
  • 循环数组
    循环可以与间接或索引寻址一起使用来操纵结构数组。
; 循环数组
INCLUDE Irvine32.incNumPoints = 3
.dataALIGN WORDAllPoints COORD NumPoints DUP(<0, 0>).code
main PROCmov edi, 0              ; 数组索引mov ecx, NumPoints      ; 循环计数mov ax, 1               ; 开始X, Y的值L1:mov (COORD PTR AllPoints[edi]).X, axmov (COORD PTR AllPoints[edi]).Y, axadd edi, TYPE COORDinc axLOOP L1exit
main ENDP
END
4). 示例: 显示系统时间
; 显示时间
INCLUDE Irvine32.inc; 相关结构体在SmallWin.inc中.datasysTime SYSTEMTIME <>XYPos COORD <10, 5>consoleHandle DWORD ?colonStr BYTE ":", 0
.code
main PROC; 获取Win32控制台标准输出句柄INVOKE GetStdHandle, STD_OUTPUT_HANDLEmov consoleHandle, eax; 设置光标位置和获取系统时间INVOKE SetConsoleCursorPosition, consoleHandle, XYPosINVOKE GetLocalTime, ADDR sysTime; 显示系统时间(hh:mm:ss)movzx eax, sysTime.wHourcall WriteDecmov edx,OFFSET colonStrcall WriteStringmovzx eax, sysTime.wMinutecall WriteDeccall WriteStringmovzx eax, sysTime.wSecondcall WriteDeccall Crlfcall WaitMsgexit
main ENDP
END
ShowTime 效果.png

5). 结构体包含结构体

结构体可以在内部字段中包含其他结构体。

Rectangle STRUCTUpperLeft COORD <>LowerRight COORD <>
Rectangle ENDS

定义及初始化:

rect1 Rectangle < >
rect2 Rectangle { }
rect3 Rectangle { {10,10}, {50,20} }
rect4 Rectangle < <10,10>, <50,20> >
6). 定义和使用共用体

虽然结构中的每个字段都具有相对于结构的第一个字节的偏移量,但联合中的所有字段都以相同的偏移量开始。 union的存储大小等于其最长字段的长度。

格式:

unionname UNIONunion-fields
unionname ENDS

如果在结构体定义共用体,则格式如下

structname STRUCTstructure-fieldsUNION unionnameunion-fieldsENDS
structname ENDS
  • 始终如一
    先定义一个Integer共用体,再定义myInt共用体变量,此时未进行初始化,那么myInt.D, myInt.W, myInt.B的值都为1
Integer UNIOND DWORD 1W WORD 5B BYTE 8
Integer ENDS.datamyInt Integer <>
  • 结构体中包含共用体
    可以在结构体中包含一个在外部定义的共用体或者在结构体内部定义共用体。
; 结构体外部定义共用体
FileInfo STRUCTFileID Integer <>FileName BYTE 64 DUP(?)
FileInfo ENDS; 结构体内部定义共用体
FileInfo STRUCTUNION FileIDD DWORD ?W WORD ?B BYTE ?ENDSFileName BYTE 64 DUP(?)
FileInfo ENDS
  • 定义和使用共用体变量
    union变量的声明和初始化方式与结构变量的方式大致相同,但有一个重要区别:允许的初始值不超过一个。
val1 Integer <12345678h>
val2 Integer <100h>
val3 Integer <>

共用体中也可以包含结构体

INPUT_RECORD STRUCTEventType WORD ?ALIGN DWORDUNION EventKEY_EVENT_RECORD <>MOUSE_EVENT_RECORD <>WINDOW_BUFFER_SIZE_RECORD <>MENU_EVENT_RECORD <>FOCUS_EVENT_RECORD <>ENDS
INPUT_RECORD ENDS; 其中KEY_EVENT_RECORD结构
KEY_EVENT_RECORD STRUCTbKeyDown DWORD ?wRepeatCount WORD ?wVirtualKeyCode WORD ?wVirtualScanCode WORD ?UNION uCharUnicodeChar WORD ?AsciiChar BYTE ?ENDSdwControlKeyState DWORD ?
KEY_EVENT_RECORD ENDS

2. 宏

宏过程是汇编语言语句的命名块。 一旦定义,就可以根据需要在程序中多次调用(调用)它。 当您调用宏过程时,其代码的副本将直接插入到调用它的位置的程序中。

  • 位置
    宏定义通常出现在程序源代码的开头,或者它们被放在一个单独的文件中,并通过INCLUDE指令复制到程序中。 在汇编程序的预处理步骤中扩展宏

定义格式:

PrintX MACROmov al,'X'call WriteChar
ENDM
1). 宏定义

宏定义使用 MACROENDM.

格式:

macroname MACRO parameter-1, parameter-2...statement-list
ENDM
  • 宏参数
    宏参数被命名为传递给调用者的文本参数的占位符, 参数可以是整数,变量或其他值,预处理器将它们视为文本。

  • mPutchar 示例

mPutchar MACRO charpush eaxmov al,charcall WriteCharpop eax
ENDM
2). 调用宏

通过在程序中插入宏来调用宏,可能后跟宏参数。

macroname argument-1, argument-2, ...

调用mPutchar代码:mPutchar 'A'

3). 其他宏功能
  • 必要参数
    使用REQ修饰符,标记宏参数是必要的。
mPutchar MACRO char:REQpush eaxmov al,charcall WriteCharpop eax
ENDM
  • 宏注释
    每次扩展宏时,都会出现宏定义中出现的普通注释行。 如果要从宏扩展中省略注释,请在前面加上双分号(;;)
mPutchar MACRO char:REQpush eax            ;; reminder: char must contain 8 bitsmov al,charcall WriteCharpop eax
ENDM
  • ECHO 指令
    当程序汇编时,ECHO指令将字符串写入标准输出.
mPutchar MACRO char:REQECHO Expanding the mPutchar macropush eaxmov al,charcall WriteCharpop eax
ENDM
  • LOCAL 指令
    为避免标签重新定义导致的问题,可以将LOCAL指令应用于宏定义内的标签。 当标签标记为LOCAL时,预处理器会在每次扩展宏时将标签名称转换为唯一标识符。
makeString MACRO textLOCAL string.datastring BYTE text,0
ENDM
  • 宏包含变量和代码
mWrite MACRO textLOCAL string ;; local label.datastring BYTE text,0 ;; define the string.codepush edxmov edx,OFFSET stringcall WriteStringpop edx
ENDM
  • 嵌套宏
    从另一个宏调用的宏称为嵌套宏。
mWriteln MACRO textmWrite textcall Crlf
ENDM
4). Macro 库(32位)
Macros in the Macros.inc Library.png

  • mDumpMem
    mDumpMem宏在控制台窗口中显示一块内存。
.data
array DWORD 1000h,2000h,3000h,4000hmDumpMem OFFSET array, LENGTHOF array, TYPE array

宏实现:

;------------------------------------------------------
mDumpMem MACRO address:REQ, itemCount:REQ, componentSize:REQ
; Displays a dump of memory, using the DumpMem procedure.
; Receives: memory offset, count of the number of items
; to display, and the size of each memory component.
; Avoid passing EBX, ECX, and ESI as arguments.
;------------------------------------------------------push ebxpush ecxpush esimov esi,addressmov ecx,itemCountmov ebx,componentSizecall DumpMempop esipop ecxpop ebx
ENDM
  • mDump
    mDump 宏用十六进制显示变量的地址和值。
.datadiskSize DWORD 12345h
.codemDump diskSize      ; no labelmDump diskSize,Y    ; show label

宏实现:

;----------------------------------------------------
mDump MACRO varName:REQ, useLabel
;
; Displays a variable, using its known attributes.
; Receives: varName, the name of a variable.
; If useLabel is nonblank, the name of the
; variable is displayed.
;----------------------------------------------------call CrlfIFNB <useLabel>mWrite "Variable name: &varName"ENDIFmDumpMem OFFSET varName, LENGTHOF varName, TYPE varName
ENDM
  • mGotoxy
    mGotoxy宏将光标定位在控制台窗口缓冲区中的特定列和行位置。
mGotoxy 10,20 ; immediate values
mGotoxy row,col ; memory operands
mGotoxy ch,cl ; register values

宏实现:

;------------------------------------------------------
mGotoxy MACRO X:REQ, Y:REQ
;
; Sets the cursor position in the console window.
; Receives: X and Y coordinates (type BYTE). Avoid
; passing DH and DL as arguments.
;------------------------------------------------------push edxmov dh,Ymov dl,Xcall Gotoxypop edx
ENDM
  • mReadString
    mReadString宏从键盘输入一个字符串,并将该字符串存储在缓冲区中。
.datafirstName BYTE 30 DUP(?)
.codemReadString firstName

宏实现:

;------------------------------------------------------
mReadString MACRO varName:REQ
;
; Reads from standard input into a buffer.
; Receives: the name of the buffer. Avoid passing
; ECX and EDX as arguments.
;------------------------------------------------------push ecxpush edxmov edx,OFFSET varNamemov ecx,SIZEOF varNamecall ReadStringpop edxpop ecx
ENDM
  • mShow
    mShow宏以调用者选择的格式显示任何寄存器或变量的名称和内容。
mov ax,4096
mShow AX        ; default options: HIN
mShow AX,DBN    ; unsigned decimal, binary, newline
  • mShowRegister
    mShowRegister宏以十六进制显示单个32位寄存器的名称和内容。
mShowRegister EBX, ebx

宏实现:

;---------------------------------------------------
mShowRegister MACRO regName, regValue
LOCAL tempStr
;
; Displays a register's name and contents.
; Receives: the register name, the register value.
;---------------------------------------------------.datatempStr BYTE " &regName=",0.codepush eax; Display the register namepush edxmov edx,OFFSET tempStrcall WriteStringpop edx; Display the register contentsmov eax,regValuecall WriteHexpop eax
ENDM
  • mWriteSpace
    mWriteSpace宏在控制台输出一个或多个空格。
; 默认为1
mWriteSpace 5

宏实现:

;------------------------------------------------------
mWriteSpace MACRO count:=<1>
;
; Writes one or more spaces to the console window.
; Receives: an integer specifying the number of spaces.
; Default value of count is 1.
;------------------------------------------------------LOCAL spaces.dataspaces BYTE count DUP(' '),0.codepush edxmov edx,OFFSET spacescall WriteStringpop edx
ENDM
  • mWriteString
    mWriteString宏向控制台输出一个字符串变量的值。
.datastr1 BYTE "Please enter your name: ",0
.codemWriteString str1

宏实现:

;------------------------------------------------------
mWriteString MACRO buffer:REQ
;
; Writes a string variable to standard output.
; Receives: string variable name.
;------------------------------------------------------push edxmov edx,OFFSET buffercall WriteStringpop edx
ENDM
5). 示例:包装
; Macros 包装程序
; 使用Macros库中的:mGotoxy, mWrite, mWriteString
; mReadString, and mDumpMem.INCLUDE Irvine32.inc
INCLUDE Macros.inc          ; macro 定义.dataarray DWORD 1, 2, 3, 4, 5, 6, 7, 8firstName BYTE 31 DUP(?)lastName BYTE 31 DUP(?).code
main PROCmGotoxy 0, 0mWrite <"Sample Macro Program", 0dh, 0ah>; 输出用户信息mGotoxy 0, 5mWrite "Please enter your first name: "mReadString firstNamecall CrlfmWrite "Please enter your last name: "mReadString lastNamecall Crlf; 显示用户姓名mWrite "Your name is "mWriteString firstNamemWriteSpacemWriteString lastNamecall Crlf; 显示整型数组mDumpMem OFFSET array, LENGTHOF array, TYPE arraycall WaitMsgcall Crlfexit
main ENDP
END
Wraps.png

3. 条件装配指令

许多不同的条件汇编指令可以与宏结合使用,以使它们更加灵活。

IF conditionstatements
[ELSEstatements]
ENDIF
Conditional-Assembly Directives.png

1). 检查丢失的参数

宏可以检查它的任何参数是否为空。 通常,如果宏接收到空白参数,则在预处理器扩展宏时会产生无效指令。

mWriteString MACRO stringIFB <string>ECHO -------------------------------------------ECHO * Error: parameter missing in mWriteStringECHO * (no code generated)ECHO -------------------------------------------EXITMENDIFpush edxmov edx,OFFSET stringcall WriteStringpop edx
ENDM
2). 参数的默认值

宏可以设置参数的默认值,如果用户没有为参数设置值,则使用该参数的默认值。

paramname := < argument >

示例:

mWriteln MACRO text:=<" ">mWrite textcall Crlf
ENDM
3). Boolean 表达式
LT Less than
GT Greater than
EQ Equal to
NE Not equal to
LE Less than or equal to
GE Greater than or equal to
4). IF, ELSE, and ENDIF 指令

IF指令必须后跟一个常量布尔表达式。 表达式可以包含整数常量,符号常量或常量宏参数,但不能包含寄存器或变量名称。

IF expressionstatement-list
ENDIFIF expressionstatement-list
ELSEstatement-list
ENDIF

示例:

;-----------------------------------------------------
mGotoxyConst MACRO X:REQ, Y:REQ
;
; Sets the cursor position at column X, row Y.
; Requires X and Y coordinates to be constant expressions
; in the ranges 0 <= X < 80 and 0 <= Y < 25.
;------------------------------------------------------LOCAL ERRS ;; local constantERRS = 0IF (X LT 0) OR (X GT 79)ECHO Warning: First argument to mGotoxy (X) is out of range.ECHO ******************************************************ERRS = 1ENDIFIF (Y LT 0) OR (Y GT 24)ECHO Warning: Second argument to mGotoxy (Y) is out of range.ECHO ******************************************************ERRS = ERRS + 1ENDIFIF ERRS GT 0 ;; if errors found,EXITM;; exit the macroENDIFpush edxmov dh,Ymov dl,Xcall Gotoxypop edx
ENDM
5). IFIDN 和 IFIDNI 指令

IFIDNI指令在两个符号(包括宏参数名称)之间执行不区分大小写的匹配,如果它们相等则返回true。 IFIDN指令执行区分大小写的匹配。 当您想要确保宏的调用者没有使用可能与宏内的寄存器使用冲突的寄存器参数时,前者很有用。

IFIDNI <symbol>, <symbol>statements
ENDIF

使用:

;------------------------------------------------------
mReadBuf MACRO bufferPtr, maxChars
;
; Reads from the keyboard into a buffer.
; Receives: offset of the buffer, count of the maximum
; number of characters that can be entered. The
; second argument cannot be edx or EDX.
;------------------------------------------------------IFIDNI <maxChars>,<EDX>ECHO Warning: Second argument to mReadBuf cannot be EDXECHO **************************************************EXITMENDIFpush ecxpush edxmov edx,bufferPtrmov ecx,maxCharscall ReadStringpop edxpop ecx
ENDM
6). 特殊的运算符
Special Operators.png

  • Substitution Operator (&)
    substitution(&)运算符解决了宏中参数名称的模糊引用。
.code
mShowRegister ECXmShowRegister MACRO regName
.data
tempStr BYTE " &regName=",0打印结果:
EAX = 00000101效果用于显示寄存器名
  • Expansion Operator (%)
    扩展运算符(%)扩展文本宏或将常量表达式转换为其文本表示形式。
count = 10
sumVal TEXTEQU %(5 + count) ; = "15"
  • Literal-Text Operator (< >)
    Literal-Text Operator(<>)将一个或多个字符和符号分组到单个文本文本中。
mWrite <"Line three", 0dh, 0ah>
  • Literal-Character Operator (!)
    Literal-Character Operator (!)的发明与文字文本运算符的目的大致相同:它强制预处理器将预定义的运算符视为普通字符。
BadYValue TEXTEQU <Warning: Y-coordinate is !> 24>
ShowWarning MACRO message
mWrite "&message"
ENDM;打印结果:
Warning: Y-coordinate is > 24
7). 宏函数

宏函数类似于宏过程,因为它为汇编语言语句列表指定名称。 它的不同之处在于它总是通过EXITM指令返回一个常量(整数或字符串)。

IsDefined MACRO symbolIFDEF symbolEXITM <-1> ;; TrueELSEEXITM <0> ;; FalseENDIF
ENDM

4. 定义重复块

MASM有许多循环指令用于生成重复的语句块:
WHILE,REPEAT,FOR和FORC。 与LOOP指令不同,这些指令仅在汇编时工作,使用常量值作为循环条件和计数器:

  • WHILE指令基于布尔表达式重复语句块。
  • REPEAT指令根据计数器的值重复语句块。
  • FOR指令通过迭代符号列表来重复语句块。
  • FORC指令通过迭代一串字符来重复语句块。
1). WHILE 指令

WHILE指令基于布尔表达式重复语句块。

WHILE constExpressionstatements
ENDM

示例:

.dataval1 = 1val2 = 1DWORD val1 ; first two valuesDWORD val2val3 = val1 + val2WHILE val3 LT 0F0000000hDWORD val3val1 = val2val2 = val3val3 = val1 + val2ENDM
2). REPEAT 指令

REPEAT指令根据计数器的值重复语句块。

REPEAT constExpressionstatements
ENDM

示例:

WEEKS_PER_YEAR = 52
WeatherReadings STRUCTlocation BYTE 50 DUP(0)REPEAT WEEKS_PER_YEARLOCAL rainfall, humidityrainfall DWORD ?humidity DWORD ?ENDM
WeatherReadings ENDS
3). FOR 指令

FOR指令通过迭代符号列表来重复语句块。

FOR parameter,<arg1,arg2,arg3,...>statements
ENDM

示例:

COURSE STRUCTNumber BYTE 9 DUP(?)Credits BYTE ?
COURSE ENDS; A semester contains an array of courses.
SEMESTER STRUCTCourses COURSE 6 DUP(<>)NumCourses WORD ?
SEMESTER ENDS.dataFall2013 SEMESTER <>Spring2014 SEMESTER <>Summer2014 SEMESTER <>Fall2014 SEMESTER <>FOR semName,<Fall2013,Spring2014,Summer2014,Fall2014>semName SEMESTER <>ENDM
4). FORC 指令

FORC指令通过迭代一串字符来重复语句块。

FORC parameter, <string>statements
ENDM

示例:

Delimiters LABEL BYTE
FORC code,<@#$%^&*!<!>>BYTE "&code"
ENDM

汇编开发(八):结构体与宏相关推荐

  1. 【VS开发】【编程开发】【C/C++开发】结构体中的数组与指针的内存分配情况说明...

    [VS开发][编程开发][C/C++开发]结构体中的数组与指针的内存分配情况说明 标签:[VS开发] [编程开发] 主要是疑惑在结构体定义的数组的内存空间与指针动态分配的内存空间,在地址上连续性.以及 ...

  2. c语言程序设计实验8,C语言程序设计实验八结构体.doc

    C语言程序设计实验八结构体 C语言程序设计实验八:结构体 请求用户输入若干个学生的基本情况,其中包括每位学生的学号.姓名和两门课(C语言.数学)的成绩.然后用下面的格式输出学生的成绩列表. 格式描述如 ...

  3. X86汇编中的结构体STRUCT和UNION

    X86汇编中的结构体STRUCT和UNION 结构的定义 ; 定义名为Person的结构体 Person STRUCTidNum byte "000000"lastName byt ...

  4. windows内核开发笔记七:内核开发OVERLAPPED结构体详解

    windows内核开发笔记七:内核开发OVERLAPPED结构体详解 typedef struct _OVERLAPPED {   DWORD Internal;   DWORD InternalHi ...

  5. 从零开发区块链应用(八)--结构体初识

    文章目录 一.结构体定义 二.初始化结构体 三.结构体的访问 四.结构体指针 五.结构体可见性 六.结构体标签 七.结构体嵌套 八.结构体方法 九.结构体特性 Go语言中提供了对struct的支持,s ...

  6. 结构体,宏,枚举,函数,指针

    一.结构体 1 //定义学生的结构体 age score 2 //从终端输入4个学生的信息 3 //将这个4个学生的信息按照age升序排序 4 //输出学生的信息 5 struct stu { 6 i ...

  7. libev中ev_loop结构体中宏定义的理解

    libev源代码由于有各种宏定义,十分让人费解,作者这么写确实使得代码很简练,但也给读者的阅读带来了巨大的麻烦,下面将分析下ev_loop这个结构体的定义,加深对作者代码简化的理解,先上代码: str ...

  8. Source Insight4.0结构体使用宏定义之后,成员没关联?

    今天使用SI发现有BUG?还是就是没办法显示关联 例如: 此时没办法识别结构体指针GPIOB的成员 但如果直接把GPIOB定义为全局变量,类型为结构体指针就可以关联,如图: 但是我发现KEIL5中这种 ...

  9. 如何在内核里面查找某些结构体或者宏的定义

    想要查看一些结构体的定义,比如struct ip_mreq,可以查看头文件,所有的系统预定义的结构体都在内核源代码的/include下有定义,ubuntu里面是/usr/include .  比如要找 ...

最新文章

  1. 解决报错:gpg: keyserver receive failed: No dirmngr
  2. java logic_java logic怎么做用户登录
  3. 学校(School)主要有3大角色:学校(School),讲师(Teacher),学员(Student)。请用Python语言简要实现这些类及及其属性,以及它们之间的关系。
  4. WPF简单的口算案例
  5. 如何在SAP Kyma的控制台里扩展新的UI
  6. 向linux内核增加新的系统调用,为linux内核添加新的系统调用
  7. js中 json详解
  8. 【逆强化学习-0】Introduction
  9. 怎么让人爆照_瞬间变上相,让照片颜值大爆棚的跳跃照技巧
  10. 【note】Head First Java笔记
  11. poj1270_toposort+回溯
  12. Delphi 2010手动安装indy10.5.7
  13. 19本高并发编程书籍推荐
  14. 如何生成WIFI二维码供手机扫一扫连接WIFI
  15. 如何保留5个有效数字输出c不4舍5入_好吃好喝不发胖,这样过年才健康团
  16. [C#] DataView用法
  17. 惠州生物实验室建设宝典
  18. 帧内预测——initAdiPattern
  19. 人口普查分析:利用python+百度文字识别提取图片中的表格数据
  20. 知云文献翻译打不开_还在为论文翻译烦恼吗?点进来帮您解决

热门文章

  1. Android Studio 查看db文件
  2. 业务需求访谈之求生法则(已发表在IT168)
  3. 落寞的枭雄家乐福中国,如何挽回颓势?
  4. 数据库2:SELECT-天池龙珠计划SQL训练营
  5. https://mp.weixin.qq.com/s/z9sEM1sSOY1wnKjaTiSOsg
  6. SteamVR 2.0 Unity插件使用指南
  7. python之pdfminer:从PDF文档中抽取信息的工具
  8. 给tomcat增加内存
  9. oracle增量备份语法,Oracle增量备份的机制
  10. 第三课:钱难赚,保险别乱买