⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 subject_46985.htm

📁 vc
💻 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>&nbsp;&nbsp;if (!str) return; <BR>&nbsp;&nbsp;str[0] = 'A'; <BR>} <BR><BR>int main() <BR>{ <BR>&nbsp;&nbsp;char *p = "Hello world!"; <BR>&nbsp;&nbsp;char *q = (char *)malloc(100); <BR><BR>&nbsp;&nbsp;//foo(p); <BR>&nbsp;&nbsp;//printf("%s\n", p); <BR>&nbsp;&nbsp;printf("&amp;a: %xd\n",&amp;a);<BR>&nbsp;&nbsp;printf("&amp;b: %xd\n",&amp;b);<BR>}<BR>编译运行后结果如下:<BR>&amp;a: 405040d<BR>&amp;b: 403010d<BR><BR>如果将int a;int b = 10;改成:int a; int b;<BR>则是如下的运行结果:<BR>&amp;a: 405040d<BR>&amp;b: 405050d<BR><BR>如果将int a = 0;int b = 10;改成:int a; int b;<BR>则是如下的运行结果:<BR>&amp;a: 403010d<BR>&amp;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&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte ptr [eax],41h<BR>00401291&nbsp;&nbsp; pop&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ebp<BR>00401292&nbsp;&nbsp; ret<BR>00401293&nbsp;&nbsp; dec&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; eax<BR>00401294&nbsp;&nbsp; ins&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte ptr [edi],dx<BR>00401296&nbsp;&nbsp; ins&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte ptr [edi],dx<BR>00401297&nbsp;&nbsp; outs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dx,dword ptr [esi]<BR>00401298&nbsp;&nbsp; and&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte ptr [edi+6Fh],dh<BR>0040129B&nbsp;&nbsp; jb&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;00401309<BR>0040129D&nbsp;&nbsp; and&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dword ptr fs:[eax],eax<BR>004012A0&nbsp;&nbsp; popad<BR>004012A2&nbsp;&nbsp; cmp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 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>&nbsp;&nbsp; compiler 把形如 &#34;stringany&#34; 等等字符串识别为常量<BR>&nbsp;&nbsp; 所以形如line_1的写法是技术上的错误,虽然 MSVC v.6<BR>&nbsp;&nbsp; 可以编译通过.<BR><BR>2:两进制文件<BR>&nbsp;&nbsp; 在win32上,MSVC v.6 compiler/linker把&#34;stringany&#34;放在<BR>&nbsp;&nbsp; exe的 .rdata section, 这个section的属性是 readable.<BR><BR>3: 内存映像<BR>&nbsp;&nbsp; os的image loader加载exe到内存时,把这个section的内存页的属性设为<BR>&nbsp;&nbsp; PAGE_READONLY.<BR><BR>由1,2,3,可知运行时任何对&#34;stringany&#34;的写入行为都将导致<BR>一个 AV (access violation).<BR>请看下面的sample.<BR><BR>/*<BR>&nbsp;&nbsp; under the bug: what is wrong with your ? char *p.<BR><BR>&nbsp;&nbsp; by dr0<BR><BR>&nbsp;&nbsp; 2002/12/8<BR><BR>*/<BR><BR>#include &lt;windows.h&gt;<BR>#include &lt;stdio.h&gt;<BR>#include &lt;string.h&gt;<BR><BR>int main(int argc, char* argv[])<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;__try{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char *p = &#34;Under The Bug&#34;; // line_1: technical error, should be const char*p.<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// read memory page information<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MEMORY_BASIC_INFORMATION mbi;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset(&amp;mbi,0, sizeof(mbi));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// get the memory page &#34;Under The Bug&#34; resides<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned int base = ( (unsigned int)p / 4096 ) * 4096;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;VirtualQuery((LPVOID)base,&amp;mbi, sizeof(mbi));<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( PAGE_READONLY == (mbi.Protect &amp; (~PAGE_GUARD | PAGE_NOCACHE ) ) ) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&#34;page attribute is:&nbsp;&nbsp;PAGE_READONLY \n&#34;);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&#34;faint! what is wrong ? \n&#34;);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// raise the exception<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strcat(p, &#34;by dr0&#34;); <BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;__except(EXCEPTION_EXECUTE_HANDLER) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&#34;Wow, The lovely bug is born !\n&#34;);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return -1;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;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 + -