📄 subject_46985.htm
字号:
<p>
序号:46985 发表者:James.Q 发表日期:2003-07-16 13:27:08
<br>主题:[紧急求助]有谁真正了解外部变量的真实含义????
<br>内容:有这样一段程序:<BR>int a;<BR>int b = 10; <BR>void foo(char str[]) <BR>{ <BR> if (!str) return; <BR> str[0] = 'A'; <BR>} <BR><BR>int main() <BR>{ <BR> char *p = "Hello world!"; <BR> char *q = (char *)malloc(100); <BR><BR> //foo(p); <BR> //printf("%s\n", p); <BR> printf("&a: %xd\n",&a);<BR> printf("&b: %xd\n",&b);<BR>}<BR>编译运行后结果如下:<BR>&a: 405040d<BR>&b: 403010d<BR><BR>如果将int a;int b = 10;改成:int a; int b;<BR>则是如下的运行结果:<BR>&a: 405040d<BR>&b: 405050d<BR><BR>如果将int a = 0;int b = 10;改成:int a; int b;<BR>则是如下的运行结果:<BR>&a: 403010d<BR>&b: 403014d<BR><BR>我想问的是:<BR>1.a和b究竟是什么变量?(我认为是外部变量)他们究竟是怎么分配的?<BR>2.为什么对a,b进行初始化和不进行初始化打印结果有区别?<BR>3.外部变量的分配应该是在编译是确定的,为什么最后一个结果才是想要的(就是两个外部变量在一起)<BR>4.int a;和int a = 10有什么区别(int a 是在函数外面的,如果是在函数内部呢?)<BR>5.变量的申明和定义究竟是什么意思?(int a;是属于申明还是定义,我认为是申明加定义,并且编译是就初始化为0)<BR>6.将foo(p)的注释去掉,将会出现0x0040128e指令引用的0x00401293内存.该内存不能为writen....好像p是指向了代码段.为什么会这样,究竟参数是怎么入栈和变量是怎么分配的?<BR><BR>我刚学c语言(现在主要用的是java),希望各位大侠能指点迷津!!!
<br><a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p>
<hr size=1>
<blockquote><p>
<font color=red>答案被接受</font><br>回复者:Fang 回复日期:2003-07-16 14:41:39
<br>内容:-----我刚学c语言(现在主要用的是java),希望各位大侠能指点迷津!!! <BR>刚刚学习就问得这么有深度,佩服。<BR><BR>这个问题,一般来说,不同的编译器,不同的平台有不同的实现。或者说,这是编译器的内部问题,我们不用管太多。<BR><BR>以下回答基于win2000,vc6平台。<BR><BR>1.a和b究竟是什么变量?(我认为是外部变量)他们究竟是怎么分配的?<BR>当然是外部变量。<BR><BR>windows平台pe文件格式有两个数据段,.data 和 .rdata段。<BR>a,b都不是只读数据,当然应该在 .data中。<BR><BR>2.为什么对a,b进行初始化和不进行初始化打印结果有区别?<BR>3.外部变量的分配应该是在编译是确定的,为什么最后一个结果才是想要的(就是两个外部变量在一起)<BR><BR>这个问题让我汗颜,没有找到答案。只是发现初始化数据出现在.data段前部,未初始化放在.data后部。vc这样做是为什么,我不知道。<BR><BR>4.int a;和int a = 10有什么区别(int a 是在函数外面的,如果是在函数内部呢?)<BR>5.变量的申明和定义究竟是什么意思?(int a;是属于申明还是定义,我认为是申明加定义,并且编译是就初始化为0)<BR><BR>如果在函数内部,就不叫外部变量了,在.data段也找不到了,函数内部的局部变量(非static!)都是在栈中。<BR><BR>声明和定义有很大区别。细节不讲了。int a;既是声明也是定义。是不是初始化成0的问题,一般来说,...反正vc6是初始化成0的,我猜想这也是未初始化变量放在.data末尾的原因。<BR><BR>6.将foo(p)的注释去掉,将会出现0x0040128e指令引用的0x00401293内存.该内存不能为writen....好像p是指向了代码段.为什么会这样,究竟参数是怎么入栈和变量是怎么分配的?<BR><BR>有关这个事,我还发现了一系列的“怪事”:<BR>1,Debug版,foo(p);//去掉,“Hello World”出现在.rdata数据段(不是代码段)。所以可以解释非法访问(不可写)的问题。(你的“0x0040128e指令引用的0x00401293内存”似乎真的是在代码段?代码段也是只读的)<BR>2,Release版,foo(p);//去掉,“Hello World”出现在.data数据段,当然可以写。printf出现“Aello World”.<BR><BR>pe格式介绍文章网上可以找到。<BR>察看pe格式的工具dumpbin就可以了。vc自带工具。\bin目录下。
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:James.Q 回复日期:2003-07-16 17:01:17
<br>内容:非常感谢大侠的解答,我明白了一些问题.我上学时学过c,还是有过基础的,不过没用过vc,对win下编程不了解,这个程序还是我在win2k下用gcc编的,编控制台程序比较方便吧.我有运行了一下这个程序,结果如下:<BR>出现0x0040128e指令引用的0x00401293内存.该内存不能为writen....<BR>调试程序后,出现以下结果:<BR>0040128E mov byte ptr [eax],41h<BR>00401291 pop ebp<BR>00401292 ret<BR>00401293 dec eax<BR>00401294 ins byte ptr [edi],dx<BR>00401296 ins byte ptr [edi],dx<BR>00401297 outs dx,dword ptr [esi]<BR>00401298 and byte ptr [edi+6Fh],dh<BR>0040129B jb 00401309<BR>0040129D and dword ptr fs:[eax],eax<BR>004012A0 popad<BR>004012A2 cmp ah,byte ptr [eax]<BR>可以看出00401293 dec eax是指向程序代码.因为好像在linux下也会出现这个问题,所以我不知道参数是怎么传进去的.希望大侠能给予一条路.
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:Fang 回复日期:2003-07-16 18:18:16
<br>内容:访问出错的原因是str[0] = 'A'; 因为str[0]也就是“Hello World”中的'H',在代码段,代码段不可写,所以访问违例。----这就是我猜测的解释。<BR><BR>str的声明仅仅表明它是指针,p是指向“Hello World”的指针。和参数入栈没有关系。<BR><BR>如果char p[]="Hello World";那又不同了:p指向栈内的“Hello World”处。编译器会从不可读的代码段或者数据段把“Hello World”复制到栈内的空间p[]。<BR>
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:xiongli 回复日期:2003-10-09 10:05:21
<br>内容:6.将foo(p)的注释去掉,将会出现0x0040128e指令引用的0x00401293内存.该内存不能为writen....好像p是指向了代码段.为什么会这样,究竟参数是怎么入栈和变量是怎么分配的?<BR>//参考写作区dr0的what's wrong 系列文章:<BR><BR>原作者姓名 dr0<BR>介绍<BR>下面的代码片断描述了一个常见的bug, 网上很多文章讨论过但是<BR>大都模模糊糊,我抽空研究了一下,总结如下.<BR><BR>读者评分 4 评分次数 1 <BR><BR>正文<BR>1: 编译器<BR> compiler 把形如 "stringany" 等等字符串识别为常量<BR> 所以形如line_1的写法是技术上的错误,虽然 MSVC v.6<BR> 可以编译通过.<BR><BR>2:两进制文件<BR> 在win32上,MSVC v.6 compiler/linker把"stringany"放在<BR> exe的 .rdata section, 这个section的属性是 readable.<BR><BR>3: 内存映像<BR> os的image loader加载exe到内存时,把这个section的内存页的属性设为<BR> PAGE_READONLY.<BR><BR>由1,2,3,可知运行时任何对"stringany"的写入行为都将导致<BR>一个 AV (access violation).<BR>请看下面的sample.<BR><BR>/*<BR> under the bug: what is wrong with your ? char *p.<BR><BR> by dr0<BR><BR> 2002/12/8<BR><BR>*/<BR><BR>#include <windows.h><BR>#include <stdio.h><BR>#include <string.h><BR><BR>int main(int argc, char* argv[])<BR>{<BR> __try{<BR> char *p = "Under The Bug"; // line_1: technical error, should be const char*p.<BR> // read memory page information<BR> MEMORY_BASIC_INFORMATION mbi;<BR> memset(&mbi,0, sizeof(mbi));<BR> // get the memory page "Under The Bug" resides<BR> unsigned int base = ( (unsigned int)p / 4096 ) * 4096;<BR><BR> VirtualQuery((LPVOID)base,&mbi, sizeof(mbi));<BR> if( PAGE_READONLY == (mbi.Protect & (~PAGE_GUARD | PAGE_NOCACHE ) ) ) {<BR> printf("page attribute is: PAGE_READONLY \n");<BR> }<BR> else {<BR> printf("faint! what is wrong ? \n");<BR> }<BR> // raise the exception<BR> strcat(p, "by dr0"); <BR> }<BR> __except(EXCEPTION_EXECUTE_HANDLER) {<BR> printf("Wow, The lovely bug is born !\n");<BR> return -1;<BR> }<BR> return 0;<BR>}<BR><BR><BR>正文完<BR><BR>http://www.vchelp.net/itbookreview/view_paper.asp?paper_id=534
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -