Win32汇编备份--C嵌入汇编

C嵌入汇编

  1. 键盘输入任一个字符,然后以此字符填充数组a[41]。
    注意:填充40个字符即可。
    如:
    运行后输入:A
    则结果输出:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    请在//和//之间编写程序。
    注意:不要删除或增加//和//。
#include "stdio.h"
void main()
{
char a[41]={0},c;
scanf("%c",&c );
	__asm
	{
/*【*/
LEA EDI,a
		LEA ESI,c
		MOV ESI,DWORD PTR[ESI]
		MOV ECX,40
		again:
			MOV DWORD PTR[EDI],ESI
			ADD EDI,1
		LOOP again
/*】*/
	}
	printf("%s",a);
}


#include "stdio.h"
void main()
{
char a[41]={0},c;
scanf("%c",&c );
	__asm
	{
/*【*/
CLD
mov al,c
lea edi,a
mov ecx,40
rep stosb
/*】*/
	}
	printf("%s",a);
}
  1. 将字符数组a[63]中的数字删除(相当于把字母移到起始位置)。
    注意:字符串结束标志也移。
    如:
    运行后输入:null(不输入)
    则结果输出:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
    请在//和//之间编写程序。
    注意:不要删除或增加//和//。
#include "stdio.h"
void main()
{
char a[63]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
	__asm
	{
/*【*/
CLD
LEA ESI,a+10
LEA EDI,a
MOV ECX,53
rep movsb
/*】*/
	}
	printf("%s",a);
}
  1. 键盘输入任一个整数n和一个汉字(即两个字符),然后以此汉字填充p指定位置。
    注意:最多填充40个汉字(n<=40)。
    如:
    运行后输入:4 字
    则结果输出:字字字字
    请在//和//之间编写程序。
    注意:不要删除或增加//和//。
#include "stdio.h"
void main()
{
char c1,c2,p[81]={0};
int n;
scanf("%d %c%c",&n,&c1,&c2);
	__asm
	{
/*【*/
CLD
LEA EDI,p
MOV AL,c1
MOV AH,c2
MOV ECX,n
rep stosw
/*】*/
	}
	printf("%s",p);
}
  1. 将字符数组a[63]中的字母向后移10个位置。
    注意:前10个位置字母不变。
    如:
    运行后输入:null(不输入)
    则结果输出:ABCDEFGHIJABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
    请在//和//之间编写程序。
    注意:不要删除或增加//和//。
    思路:此题较为特殊,使用STD为方向标志逆序填充字符,所以两个字符串首地址都做了改变,ESI首地址指向字符串的z,EDI指向9,ESI从9开始将EDI填充(9=z,8=y…)直到循环结束,这时便可以得出答案。此题整个字符串a的长度62,因为a的长度计算由0开始,所以首地址加上61便可以指向字符串末尾,加上51便可以指向z。
#include "stdio.h"
void main()
{
char a[63]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",c;
	__asm
	{
/*【*/
STD
LEA ESI,a+51
LEA EDI,a+61
MOV ECX,52
rep movsb
CLD
/*】*/
	}
	printf("%s",a);
}
  1. 键盘输入一串字符给数组a,然后请你将其复制到数组b。
    如:
    运行后输入:ABCDEFG
    则结果输出:ABCDEFG
    请在//和//之间编写程序。
    注意:不要删除或增加//和//。
#include "stdio.h"
void main()
{
char a[80],b[80];
scanf("%s",a);
	__asm
	{
/*【*/
CLD
LEA ESI,a
LEA EDI,b
MOV ECX,79
rep movsb
/*】*/
	}
	printf("%s",b);
}
  1. 键盘输入整数x、y、z,然后输出xy+z的值。
    运行后若输入:3 4 5
    则结果输出:3
    4+5=17
    请在//和//之间编写程序。
#include "stdio.h"
void main()
{
	int x,y,z,t;
	scanf("%d %d %d",&x,&y,&z);
	__asm
	{
/*【*/
MOV EAX,x
IMUL EAX,y
ADD EAX,z
MOV t,EAX
/*】*/
	}
	printf("%d*%d+%d=%d",x,y,z,t);
}

after all

MOVSB MOVSW MOVSD 指令描述及用法

目前80386系列的处理器提供几组处理字节、字和双字数值的指令,尽管这些指令成为基本字符串指令,但他们的用法并不局限于字符数组。

指令:
MOVSB, MOVSW, MOVSD

描述:
移动字符串数据,复制由ESI寄存器寻址的内存地址处的数据至EDI寻址的内存地址处。

在保护模式程序中,也就是我们80386默认的启动模式,ESI自动作为由DS寻址的段内偏移,EDI自动作为由ES寻址的段内偏移,ES和DS总是具有同样的值且无法改变它们。(在实地址模式(8086)模式下ES和DS是我们程序员操纵的)。

我们来看这三个指令:MOVSB, MOVSW, MOVSD ,我们可以发现它们就最后一个字母不同,其实最后一个字母也就表示的是我们每次移动的数据字节大小。第一个MOVSB是每次一个字节,其次是一个字、接着一个双字。 我们从它的’B’,‘W’,'D’就可以看出来。 B代表Byte,W代表WORD, D代表DWORD。

上面这3个字符串操作指令本身每次只能处理一个或一对值,但如果增加一个重复前缀,指令就会使用ecx寄存器作为计数器进行重复。重复前缀可以仅用一条指令处理整个数组。

重复前缀REP : 当ECX>0时重复 (和我们的loop循环相似)。

看了上面的理论,我们来个演示吧。

 cld   ;方向标志 
 mov   esi, 内存地址1     ;(也就是存放字符串的内存地址) 
 mov   edi, 内存地址2     ;(要移动到目的处的地址) 
 mov   ecx, 要移动的数量 ; 
 rep   movsb 
 
注意!在c嵌入汇编中不可用MOV,要使用LEA来获取地址,如(LEA ESI,an+2)。

cld是来控制重复移动时候的esi 和edi的递增方式。 cld是将方向标志位DF设置为0,每次rep循环的时候,esi和edi自动+1。 std是将方向标志位DF设置为1,每次rep循环的时候,esi和edi自动-1。
rep循环前缀在执行循环的时候,ecx寄存器是每次减1的。和我们的loop循环一样。
内存地址可通过加减改变头地址,例(MOV ESI,a+51)则将a的首地址往后移51。

在进行字符串操作时,千万要记住要首先设置方向标志,否则会发生不可预料的结果,两个方向标志(STD,CLD)。
使用STD可以倒序填充,CLD为正序填充,但是就算使用倒序填充在程序末尾也要使用CLD使其复位,如第四题。但是所有用法都需要设置方向标志。

STOSB STOSW STOSD 指令描述及用法

这三个指令把al/ ah/ eax的内容存储到edi指向的内存单元中,同时ecx的值根据方向标志的值增加或者减少。
使用方法和上面三个指令类似。
STOSB填入单个字节,将al附上字节值(MOV al,c)再进行如第一题操作即可。
STOSW填入一个字,会分别将al,ah中的值填入,比如第三题填入中文,一个汉字占两个字节,所以使用两个字符输入汉字,并且将其存放在al,ah两个寄存器中,然后使用此指令填入字符串。
STOSD填入一个双字(DWORD),将EAX中的值重复填入一个串中。


考题(IMPORTANT!!!)

键盘输入整数x、y、z,然后输出x*y-z的值。
运行后若输入:3 4 5
则结果输出:3 *4-5=7

#include "stdio.h"
void main()
{
	int x,y,z,t;
	scanf("%d %d %d",&x,&y,&z);
	__asm
	{
/*【*/
MOV EAX,x
IMUL EAX,y
SUB EAX,z
MOV t,EAX
/*】*/
	}
	printf("%d*%d-%d=%d",x,y,z,t);
}

键盘输入整数x、y、z,然后输出x/y+z的值。
运行后若输入:6 4 3
则结果输出:6/4+3=4

#include "stdio.h"
void main()
{
	int x,y,z,t;
	scanf("%d %d %d",&x,&y,&z);
	__asm
	{
/*【*/
MOV EAX,x
CDQ
IDIV y
ADD EAX,z
MOV t,EAX
/*】*/
	}
	printf("%d/%d+%d=%d",x,y,z,t);
}

键盘输入整数x、y、z,然后输出x/y-z的值。
运行后若输入:6 4 3
则结果输出:6/4-3=-2

#include "stdio.h"
void main()
{
	int x,y,z,t;
	scanf("%d %d %d",&x,&y,&z);
	__asm
	{
/*【*/
MOV EAX,x
CDQ
IDIV y
SUB EAX,z
MOV t,EAX
/*】*/
	}
	printf("%d/%d-%d=%d",x,y,z,t);
}

键盘输入整数x、y、z,然后输出x%y+z的值(其中x%y表示求x除以y的余数)。
运行后若输入:6 4 3
则结果输出:6%4+3=5

#include "stdio.h"
void main()
{
	int x,y,z,t;
	scanf("%d %d %d",&x,&y,&z);
	__asm
	{
/*【*/
MOV EAX,x
CDQ
IDIV y
ADD EDX,z
MOV t,EDX
/*】*/
	}
	printf("%d%%%d+%d=%d",x,y,z,t);
}

键盘输入整数x、y、z,然后输出x%y-z的值(其中x%y表示求x除以y的余数)。
运行后若输入:6 4 3
则结果输出:6%4-3=-1

#include "stdio.h"
void main()
{
	int x,y,z,t;
	scanf("%d %d %d",&x,&y,&z);
	__asm
	{
/*【*/
MOV EAX,x
CDQ
IDIV y
SUB EDX,z
MOV t,EDX
/*】*/
	}
	printf("%d%%%d-%d=%d",x,y,z,t);
}

键盘输入a和b两串字符,编程实现将a串和b串连接的结果存入字符数组c[50]并输出。
如:
运行后输入:ABCD abcd
则结果输出:ABCDabcd

#include "stdio.h"
#include "string.h"
void main()
{
char a[50]="ABCD",b[50]="abcd",c[50]={0};
int n,m;
scanf("%s %s",a,b);
n=strlen(a);m=strlen(b);
__asm
{
/*【*/
CLD
LEA ESI,a
LEA EDI,c
MOV ECX,n
rep movsb
CLD
LEA ESI,b
LEA EDI,c
ADD EDI,n
MOV ECX,m
rep movsb
/*】*/
}
printf("%s",c);
}

键盘输入一串字符给数组a和一个整数i与n,然后将字符串a从第i个字符开始的n个字符复制到数组b。
如:
运行后输入:ABCDEFG 2 3
则结果输出:CDE
运行后输入:ABCDEFG 0 3
则结果输出:ABC

#include "stdio.h"
void main()
{
char a[80],b[80]={0};
int i,n;
scanf("%s %d %d",a,&i,&n);
__asm
{
/*【*/
CLD
LEA ESI,a
ADD ESI,i
LEA EDI,b
MOV ECX,n
rep movsb
/*】*/
}
printf("%s",b);
}

键盘输入一串字符给数组a和一个整数i,然后将字符串a前i个字符删除(相当于把字母移到起始位置)。
如:
运行后输入:0123456789ABCDEFGH 10
则结果输出:ABCDEFGH

#include "stdio.h"
void main()
{
char a[63];
int i;
scanf("%s %d",a,&i);
__asm
{
/*【*/
CLD
LEA ESI,a
ADD ESI,i
LEA EDI,a
MOV ECX,63
rep movsb
/*】*/
	}
printf("%s",a);
}

键盘输入一串字符给数组a和一个整数i,然后将字符串a中的字符向后移i个位置。
注意:前i个位置字符不变。
如:
运行后输入:ABCDEFGHIJKLMNOPQRSTUVWXYZ 10
则结果输出:ABCDEFGHIJABCDEFGHIJKLMNOPQRSTUVWXYZ

#include "stdio.h"
void main()
{
char a[63];
int i;
scanf("%s %d",a,&i);
__asm
{
/*【*/
STD
LEA ESI,a+61
SUB ESI,i
LEA EDI,a+61
MOV ECX,62
SUB ECX,i
rep movsb
CLD
/*】*/
	}
printf("%s",a);
}

键盘输入一个整数n和一字符c,然后用n个字符c填充数组a[81]。
如:
运行后输入:8 *
则结果输出: ********

#include "stdio.h"
void main()
{
char a[81]={0},c;
int n;
scanf("%d %c",&n,&c);
__asm
{
/*【*/
CLD
MOV AL,c
LEA EDI,a
MOV ECX,n
rep stosb
/*】*/
	}
printf("%s",a);
}

键盘输入任一个整数n和一个汉字(即两个字符),然后用n个汉字填充数组s[81]。
如:
运行后输入:4 字
则结果输出:字字字字

#include "stdio.h"
void main()
{
char a,b,s[81]={0};
int n;
scanf("%d %c%c",&n,&a,&b);
__asm
{
/*【*/
CLD
MOV AL,a
MOV AH,b
LEA EDI,s
MOV ECX,n
rep stosw
/*】*/
}
printf("%s",s);
}

键盘输入任一个整数n和一个两字词语(即4个字符),然后用n个词语填充数组s[81]。
如:
运行后输入:4 汉字
则结果输出:汉字汉字汉字汉字

#include "stdio.h"
void main()
{
char a,b,c,d,s[81]={0};
int n;
scanf("%d %c%c%c%c",&n,&a,&b,&c,&d);
__asm
{
/*【*/
LEA EDI,s
MOV ECX,n
IMUL ECX,2
MOV ESI,0
MOV EBX,2
again:
MOV EAX,ESI
CDQ
IDIV EBX
CMP EDX,0
JE Tag
MOV AL,c
MOV AH,d
stosw
JMP DONE
Tag:
MOV AL,a
MOV AH,b
stosw
DONE:
INC ESI
LOOP again
/*】*/
}
printf("%s",s);
}

键盘输入一串字符给数组a,将a中的空格清除
如:
运行后输入:123 dfs cc dfsa abs n dhag s s s
则结果输出:123dfsccdfsaabsndhagsss

#include "stdio.h"
void main()
{
char a[63]={0};
gets(a);
	__asm
	{
/*【*/
CLD
LEA ESI,a
LEA EDI,a
MOV ECX,63
MOV AL,20H
again:
MOV AH,BYTE PTR[ESI]
CMP AL,AH
JNE Other
INC ESI
JMP DONE
Other:
movsb
DONE:
LOOP again
/*】*/
	}
	printf("%s",a);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值