1481c语言合法标识符,一道C语言的问题(转)

看起来有点兴趣,对于第一个问题好疑惑,虽然p指向了局部变量,但怎么会死循环呢??

只好来用他所说的第三种方法(。。。)来测试下

首先上个代码吧

#include "stdio.h"

int *p =NULL;int *fFun(void)

{int i = 0;return &i;

}void subFun(void)

{

(*p)--;

}void gFun(void)

{intj;for(j = 0;j<10;j++)

{

subFun();

printf("%d/n",j);

}

}int _tmain(int argc, _TCHAR*argv[])

{

p=fFun();

gFun();return 0;

}

简单运行下,即可发现,为什么会死循环呢,因为在subFun()执行后j都执行了--操作。。。

看来p指向的内存就是j....

如果在int j前再加个int k,则p应该指向的就是k了

即如果将gFun修改如下,则打印结果应该是*p=1111

void gFun(void)

{int k=1111;intj;

printf("*p=%d",*p);for(j = 0;j<10;j++)

{

subFun();

printf("%d/n",j);

}

}

下面再来第二段代码

#include

int _tmain(int argc, _TCHAR*argv[])

{int count = 4;int k=0;int i = 0xFEDCBA98;

printf("content at adress %p: 0x%X",&count,count);

printf("content at adress %p: 0x%X",&k,k);

printf("content at adress %p: 0x%X",&i,i);

unsignedchar * ptr = (unsigned char *)&i;for(k = 0;k<4;k++)

{

printf("content at adress %p: 0x%X",ptr,*ptr);

ptr++;

}return 0;

}

运行结果如下

a56892dad68bde950fb5991c0faf5d5e.png

从结果可以看出,可以得出几个结论:

1. 栈的生长方向是向内存小地址伸展的

2. 在windows下,多字节类型的数据,比如int,是little-endian

(BIG-ENDIAN就是低位字节排放在内存的高端,高位字节排放在内存的低端。而LITTLE-ENDIAN正好相反。)

3. 对于多字节类型的数据,它的指针是指向小内存地址的,即*(unsigned char*)&i=0x98,而不是*(unsigned char*)&i=0xFE

4. 为什么count,k,i等局部变量之间相差12字节呢?(0x64-0x58=0x58-0x4c=12)

对上面第二段代码稍作扩展,有下面代码

#include

structS{inti,j,k;

};int _tmain(int argc, _TCHAR*argv[])

{int count = 4;int k=0;

S s;int i = 0xFEDCBA98;

printf("COUNT at adress %p: 0x%X",&count,count);

printf("K at adress %p: 0x%X",&k,k);

printf("S at adress %p",&s);

printf("S.i at adress %p",&s.i);

printf("S.j at adress %p",&s.j);

printf("S.k at adress %p",&s.k);

printf("I at adress %p: 0x%X",&i,i);

// unsignedchar * ptr = (unsigned char *)&i;

//for(k = 0;k<4;k++)

// {

// printf("content at adress %p: 0x%X",ptr,*ptr);

// ptr++;

// }return 0;

}

在windows的vs2010运行结果如下

81464fec59b3ba6f9b70731752d541d2.png

从这里发现结构体的指针依然也是指向低内存地址,但为什么s.k在内存高位,而不是内存低位呢??

对上面第三段代码进行反汇编,结果如下

int _tmain(int argc, _TCHAR*argv[])

{

013B1380 push ebp//保存main函数初始地址

013B1381 mov ebp,esp //EBP设为当前堆栈指针(esp)

013B1383 sub esp,0FCh //预留252字节(0x0FCh)给函数临时变量

013B1389 push ebx //EBX 是"基地址"(base)寄存器, 在内存寻址时存放基地址

013B138A push esi //ESI/EDI 分别叫做"源/目标索引寄存器"(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串.

013B138B push edi

013B138C lea edi,[ebp-0FCh] //lea会把地址,而不是地址里的内容送入寄存器

013B1392 mov ecx,3Fh //ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器.3Fh=63

013B1397 mov eax,0CCCCCCCCh //EAX 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器.0CCCCCCCCh是int3中断

013B139C rep stos dword ptr es:[edi]//stos((store into String),意思是把eax的内容拷贝到目的地址(es:[edi]指向目标串,ds:[esi]指向源串)//dword ptr前缀告诉stos,一次拷贝双字(4个字节)的数据到目的地址//REP可以是任何字符传指令(CMPS, LODS, MOVS, SCAS, STOS)的前缀. REP能够引发其后的字符串指令被重复, 只要ecx的值不为0, 重复就会继续.//每一次字符串指令执行后, ecx的值都会减小.因为这里会重复63次(3Fh),63*4=252,刚好初始化上面预留的252字节的空间

013B139E mov eax,dword ptr [___security_cookie (13B7000h)]

013B13A3 xor eax,ebp

013B13A5 mov dword ptr [ebp-4],eax//这几句的意思是,在取到___security_cookie之后,会和当前的ebp 相异或(xor),异或的值保持在当前stack 的顶部,作函数结束标记

int count = 4;

013B13A8 mov dword ptr [ebp-0Ch],4 //0Ch = 12,ebp为函数的初始地址,所以count存在函数的高内存地址处,这里12可能是考虑最大基本类型的长度

int k=0;

013B13AF mov dword ptr [ebp-18h],0 //18h = 24

S s; //为什么这个结构体没有汇编码,而是直接赋给其12字节(两个变量之间相差8字节)??推测结构体大小计算(sizeof)应该是在编译期,而不是运行期int i = 0xFEDCBA98;

013B13B6 mov dword ptr [ebp-38h],0FEDCBA98h //38h = 56 = (36+20)

printf("COUNT at adress %p: 0x%X",&count,count);

013B13BD mov esi,esp//进入printf函数前,esi保存当前堆栈指针

013B13BF mov eax,dword ptr [ebp-0Ch] //EAX 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器.0Ch = 12

013B13C2 push eax //printf参数3压栈,这里可以发现参数是从右向左入栈

013B13C3 lea ecx,[ebp-0Ch]

013B13C6 push ecx//printf参数2压栈

013B13C7 push offset string "COUNT at adress %p: 0x%X" (13B57D0h) //printf参数1压栈

013B13CC call dword ptr [__imp__printf (13B82B0h)] //调用printf函数

013B13D2 add esp,0Ch //因为printf函数有3个参数,堆栈指针加3*4个值,恢复堆栈平衡

013B13D5 cmp esi,esp //比较esp和调用printf之前的堆栈地址是否一致(由esi保存)

013B13D7 call @ILT+305(__RTC_CheckEsp) (13B1136h) //debug函数,检查堆栈平衡

printf("K at adress %p: 0x%X",&k,k);

013B13DC mov esi,esp

013B13DE mov eax,dword ptr [ebp-18h]

013B13E1 push eax

013B13E2 lea ecx,[ebp-18h]

013B13E5 push ecx

013B13E6 push offsetstring "K at adress %p: 0x%X"(13B57B4h)

013B13EB call dword ptr [__imp__printf (13B82B0h)]

013B13F1 add esp,0Ch

013B13F4 cmp esi,esp

013B13F6 call @ILT+305(__RTC_CheckEsp) (13B1136h)

printf("S at adress %p",&s);

013B13FB mov esi,esp

013B13FD lea eax,[ebp-2Ch]

013B1400 push eax

013B1401 push offsetstring "S at adress %p"(13B57A0h)

013B1406 call dword ptr [__imp__printf (13B82B0h)]

013B140C add esp,8013B140F cmp esi,esp

013B1411 call @ILT+305(__RTC_CheckEsp) (13B1136h)

printf("S.i at adress %p",&s.i);

013B1416 mov esi,esp

013B1418 lea eax,[ebp-2Ch]

013B141B push eax

013B141C push offsetstring "S.i at adress %p"(13B5788h)

013B1421 call dword ptr [__imp__printf (13B82B0h)]

013B1427 add esp,8013B142A cmp esi,esp

013B142C call @ILT+305(__RTC_CheckEsp) (13B1136h)

printf("S.j at adress %p",&s.j);

013B1431 mov esi,esp

013B1433 lea eax,[ebp-28h]

013B1436 push eax

013B1437 push offsetstring "S.j at adress %p"(13B5770h)

013B143C call dword ptr [__imp__printf (13B82B0h)]

013B1442 add esp,8013B1445 cmp esi,esp

013B1447 call @ILT+305(__RTC_CheckEsp) (13B1136h)

printf("S.k at adress %p",&s.k);

013B144C mov esi,esp

013B144E lea eax,[ebp-24h]

013B1451 push eax

013B1452 push offsetstring "S.k at adress %p"(13B5758h)

013B1457 call dword ptr [__imp__printf (13B82B0h)]

013B145D add esp,8013B1460 cmp esi,esp

013B1462 call @ILT+305(__RTC_CheckEsp) (13B1136h)

printf("I at adress %p: 0x%X",&i,i);

013B1467 mov esi,esp

013B1469 mov eax,dword ptr [ebp-38h]

013B146C push eax

013B146D lea ecx,[ebp-38h]

013B1470 push ecx

013B1471 push offsetstring "I at adress %p: 0x%X"(13B573Ch)

013B1476 call dword ptr [__imp__printf (13B82B0h)]

013B147C add esp,0Ch

013B147F cmp esi,esp

013B1481 call @ILT+305(__RTC_CheckEsp) (13B1136h)//unsigned char * ptr = (unsigned char *)&i;//

//for(k = 0;k<4;k++)//{//printf("content at adress %p: 0x%X

",ptr,*ptr);//ptr++;//}

return 0;

013B1486 xor eax,eax

}

综上分析,有下面结论:

结构体的size计算应该发生在编译期,sizeof(struct s)=12,但结构体内部成员却是按大地址方向分配,即成员1放在最低位,成员2,成员3依次放在更高位,这样的分配是由于在结构体内,内存的分配主要是通过结构体基址+偏移量的方式,所以成员1是&s+0,成员2地址是&s+4...

同时还有以下几个问题待解决:

1. 为什么count,k,i,struct s等局部变量之间相差12字节?准确的说是8字节,虽然&count - &k =12,除掉count占用的4字节,所以就是8字节,同样struct s分配了20字节,s自身占用12字节,依然有8字节的空闲。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值