首先看如下代码:
#include <stdio.h>
struct task_struct{
int a,b,c,d,e;
};
int main()
{
struct task_struct init={1,2,3,4,5};
struct task_struct new_task={0,0,0,0,0};
struct task_struct *task[5]={&init};
struct task_struct *current=task[0];
struct task_struct *p=&new_task;
//_asm {std}
*p = *current;
//_asm{cld}
printf("%d %d %d %d %d\n",p->a,p->b,p->c,p->d,p->e);
return 0;
}
以上代码在VC6.0环境下编译运行结果为: 1 2 3 4 5
如果去掉注释,运行结果将为: 1 0 0 0 0
上面两种结果的区别在赋值语句执行前方向标志位不同。首先我们要知道:
std使方向位置位,即DF=1,cld清方向位,即DF=0,用于串操作指令中,执行操作: es:[di]=ds:[si],也即将si指定的存储单元以字节或字传送到di指定的存储单元,拷贝的方向由DF位指定。
因此,对于两种不同的运行结果,原因就很明了了:*p=*current首先被汇编成串操作指令(如下图汇编代码),由于方向位的不同导致最终拷贝结果不同,编译时默认方向位DF=0。
另外如果结构体成员比较少的话,编译器将不采用串操作,以通用寄存器直接赋值。是否采用串操作,测试GCC编译器容忍成员个数要多于VC编译器。
如果不想因为方向位问题导致*p=*current的赋值失败。可采用如下代码实现:
char *p1=(char *)p;
char *p2=(char *)current;
for(int i=0;i<sizeof(*p);i++)
*p1++=*p2++;