db ;8 bit char
dw;define word double byte short int 16bit
dd define float or long int 32 bit
dq;define quadruple word 8 byte 64 bit,double or int of 64bit
dt;define ten bytes 80bit ;long double %LF can not use to define a int
pi dd 3.14;define a float pi =3.14
x dd 1234567h; long int x=0x1234567
x dq 12345688h; int64 x=0x12345678
y dq 2.71453414; double y
;汇编里面是看具体给出的内容进行识别,如果你给的是个小数,他把当成一个小数
;__int64 vc里面专用的define 64 bit int %I64d(十进制) %I64x(16进制)
-
小端规则:
-
先存放低8位,后存放高8位
-
short int a =0x1234; a dw 1234h
-
12为高八位,34为第八位
-
1000 0x34
-
1001 0x12
-
(按着指针的顺序,先检索的到的是低8位,与我们习惯相反,所以称为小端规则)
-
-
大端规则
- 先存放高八位,再保存低八位
- 1000 0x12
- 1001 0x34
-
intel的机器为小端规则
why choose small-ending
if we long int a=0x12345678
char b=a/b=0x78/
再使用计算机的时候,我们不能明确某个地址指向的内容,除非我们加上类型修饰,这样才可以知道内容的长度
unsigned char 0,255 00h,FFh
unsigned short int 0,65535 00h,ffffh
unsigned long int 00000000h,ffffffffh;
+127
01111111
-128
100000000
- 零扩充和符号扩充
- unsigned char a =0xfe
- short int b;
- b=a;把a零扩充后赋值给b,b=0x00fe
- 如果等号右边的数为非符号,那么就使用零扩充
- 非符号数放大的时候左边永远补零,跟目标(赋值的对象 )的类型无关
- char a=0xfe;//说明这个是一个补码,是-2.因为有符号,如何知道一个补码是多少,找相反数,使和为0
- 1111110+00000010=0所以就是-2
- unsigned short int b;
- b=a;b=1111111111111110,b=0xffee,因为这里有符号,所以就直接加上1就可以
- 把一个负数(不管是多少,只要是符号数就补1)进行符号扩充,直接补1就可以,(因为只有补1才能保证原来的符号值没有改变)
- 小数保存
- 11.11 小数后面第一位代表2的-1次方,第二个1代表2的负二次方
- float
- 32位
- 0x42fec000
- 01000010 11111110 11000000 00000000
- 0 10000101 11111101100000000000000
- 划分为这三段
- 最高位的0代表符号位,与之前类似,
- 后面紧跟的8个位为偏执指数,非符号数,这个值在这里是133,然后减去127这个常数得到6,这个指数就是我们实际的指数,代表2的多少次方
- 把剩余的23位抄下来,再前面增加一个1.
- 在这里就是1.11111101100000000000000作为真实的尾数
- 最后的结果就是把之前的指数与之前的指数相乘
- 这里就是1111111.01100000000000
- 算出实际的值
- 127+1/4+1/8=127.375,而且这个是个正数
- 由于这里尾数要加上1.的规则,直接规定,如果32位全为0,那么就代表0.0
- c中char会被自动转化为int
- unsigend char前面补0,所以看不出来,但对于char来说,前面补1,所以在显示上会有所差异
add;加
sub;减
mul;乘
div;除
;加减乘除运算不可以同时操作两个变量
add a[0],a[1];语法错误,因为操作数不能同时都是内存变量,有硬件的局限,cpu做不到
;正确写法
mov ah,a[1];假设a[0]位一个byte,而ah刚好为一个byte
add a[0],ah;
add ds:[1000h],2;语法错误,因为2的宽度不确定,而左边的宽度也不确定,只能确定这个变量的首地址,不知道这个首地址具体指向的是什么,汇编中在直接运算的时候并没有自动给出变量类型
add byte ptr ds:[1000h],2; ptr pointer, byte ptr可以理解为char * 类似于强制类型转化
add word ptr ds:[1000h],2;wort pointer 相当于short int *
add dword ptr ds:[1000h],2;double word ptr相当于long int *
add a[0],1;ok
add ax,bx;寄存器,寄存器
add ax,2;寄存器,常数
add ax,ds:[1000h];寄存器,内存变量,[]表示偏移地址,ds表示段地址
add ds:[1000h],ax;内存变量,寄存器
add word ptr ds:[1000h],2;汇编语言中,常数是没有宽度的,
;汇编使用的逻辑运算
and or xor not shl(<< shift left) shr(>> shift right)
rol(循环左移 rotate lef ) ror(rotate right循环右移)
mov ah,8fh;10001111
rol ah,1;00011111,循环左移没有0填坑;可逆,不会造成位的丢失,具有可逆性
分析一下思路,
一个
abc dd 12345678h
12345678h,循环左移4位变成23456781h
再把2345 6781h and 0000 000Fh=0000 0001h
再循环左移4次变成34567812h,相当于左移1字节
再and 0000 000Fh=0000 0002h
连续做8次循环,提取到了数字的1,2,3,4,5,6,7,8
相当于是0001,0002,0003,0004,0005,0006,0007,0008
然后手动贴引号,类似于1+‘A’,实际上是asicc码转化
把他保存在数组
s db “12345678”
.386
;将8086和386混合起来使用
data segment use16
abc dd 2147483647;10进制
s db 8 dup(0),0Dh,0Ah,'$'
t dd 0
data ends
code segment use16
assume cs:code,ds:data
main:
mov ax,data
mov ds,ax;ds复制位短地址
mov eax,abc
mov cx,8
mov di,0;目标数字及s的下表
again:
rol eax,4;
push eax;保护eax的值
and eax,0Fh;这里会把eax的值给毁掉,所以需要在前面先把eax压入堆栈
cmp al,10
is_digit:
add al,'0'
jmp finish_4bits
is_alpha:
sub al,10
add al,'A'
finish_4bits:
mov s[di],al
pop eax;弹出堆栈,可以把eax的值覆盖成堆栈里面存储的eax值,如果用变量来存的话会多定义一个data并且还涉及引用,如果用寄存器的话会浪费一个寄存器,所以我们使用堆栈的方式
add di,1
sub cx,1
code ends
end main
- 段地址与偏移地址
- 一个数字的地址称为物理地址,:连接的两个数字表示的地址称为逻辑地址
- 段首地址必须要保证地址16进制的最后一位是0
- 1个物理地址可能对应着多个逻辑地址
- 段长度有限制,FFFFh为最大的偏移地址,所以长度为10000h,216次方26k及64k,