如何查看 数组实现栈在栈上的分布 汇编

Possible Duplicate:
What is the difference between declaring an array as:
int arr[100];
int* arr=(int*)malloc(sizeof(int)*100);
Which one is preferred? Is there something like heap and stack memory involved in this?
解决方案 I suggest a trip to the bookstore to pickup a copy of Kernighan and Ritchie's The C Programming Language, and optionally, a copy of Harbison & Steele's C: A Reference Manual.
The first case gives you an array of 100 ints, allocated on the stack. The latter case gives you a pointer to an int, whose address is that of a buffer allocated on the heap, the size of which is large enough to contain 100 ints.
The C language is fundamentally a hardware agnostic assembly language. The distinction between a pointer and an array is intentionally fuzzy, since array reference notation is syntactic sugar for pointer arithmetic. This:
int foo( int a )
int x[100] = load_X() ;
int y = x[ a ] ;
is identical to
int foo( int a )
= load_X() ;
= *( x + a ) ;
// note that the use of sizeof() isn't required.
For the pointer carries around
// an implicit increment size (the size of the object to which it points). The above
// is equivalent to
int y = *(int*)((char*)x + (a*sizeof(*x)) ) ;
Further, the compiler will (or should) whine about type mismatches, given function foo():
public void foo( int a[] )
The invocation:
int *p = malloc(...) ;
should results in a compiler whine regarding type mismatches.
本文地址: &
可能重复:结果
什么是声明数组作为的区别是:
INT ARR [100]; 和 为int * ARR =(INT *)malloc的(的sizeof(int)的* 100); 哪一个是preferred?有什么样参与这个堆和栈内存?解决方案 我建议去一趟书店皮卡的副本Kernighan和里奇的的 C程序设计语言的和可选的副本哈比森&安培;斯蒂尔的 C:参考手册 第一种情况为您提供了100整数数组,在栈上分配。后一种情况给你一个指针为int,其地址是在堆中分配的缓冲区,它的大小是大到足以容纳100整数。 C语言基本上是一个硬件无关的汇编语言。一个指针和数组之间的区别是故意模糊的,因为数组引用标记是作为指针运算语法糖。这样的:
INT美孚(INT一){
INT X [100] = load_X();
INT Y = X [A];
返回是;} 是相同的
INT美孚(INT一){
为int * X = load_X();
INT Y = *(X + A);
//注意,不需要使用的sizeof()。有关指针随身携带
//隐式增量大小(它指向该对象的尺寸)。以上
// INT Y = *(INT *)((字符*)X +(A *的sizeof(* X)));} 此外,编译器将(或应该)抱怨类型不匹配,给定函数富(): 公共无效美孚(int类型的[]){
...} 调用: 为int * p =的malloc(...);富(P); 应该产生一个编译器的抱怨有关类型不匹配。
本文地址: &
扫一扫关注官方微信网站已改版,请使用新地址访问:
4-4 将编号为0和1的两个栈存放于一个数组空间V[m]中,栈底分别处于 端。这种双栈结 Data structs 数据结构 238万源代码下载-
&文件名称: 4-4
& & & & &&]
&&所属分类:
&&开发工具: Visual C++
&&文件大小: 435 KB
&&上传时间:
&&下载次数: 4
&&提 供 者:
&详细说明:将编号为0和1的两个栈存放于一个数组空间V[m]中,栈底分别处于数组的两端。这种双栈结构的类定义,并实现判栈空、判栈满、插入、删除算法。-Will be numbered 0 and 1 array of two stacks placed in a space V [m], the stacks were in the bottom ends of the array. This dual-stack structure of class definitions, and to achieve sub-stack is empty, the sub-stack is full, insertion and deletion algorithms.
文件列表(点击判断是否您需要的文件,如果是垃圾请在下面评价投诉):
&&4-4\4-4\4-4.vcxproj&&...\...\4-4.vcxproj.user&&...\...\4-4.vcxproj.filters&&...\...\ReadMe.txt&&...\...\stdafx.h&&...\...\targetver.h&&...\...\stdafx.cpp&&...\...\4-4.cpp&&...\...\Debug\4-4.log&&...\...\.....\4-4.lastbuildstate&&...\...\.....\4-4.unsuccessfulbuild&&...\...\.....\vc100.idb&&...\...\.....\vc100.pdb&&...\...\.....\CL.read.1.tlog&&...\...\.....\CL.write.1.tlog&&...\4-4.sdf&&...\4-4.sln&&...\4-4.suo&&...\...\Debug&&...\ipch\4-4-fa518f80&&...\4-4&&...\ipch&&...\Debug&&4-4
&相关搜索:
&输入关键字,在本站238万海量源码库中尽情搜索:
&[] - 设有1000个值在1到10000的整数,试设计一个利用散列方法的算法,以最少的数据比较次数和移动次数对它们进行排序。
&[] - The program utilizes a circular linked list to achieve the solving of the problem of Josephus
&[] - double stack, 利用C++编写的双栈结构,比较简单基本下次自动登录
现在的位置:
& 综合 & 正文
关于进程堆栈分布和工作原理(转发)
我们经常会讨论这样的问题:什么时候数据存储在堆栈(Stack)中,什么时候数据存储在堆(Heap)中。我们知道,局部变量是存储在堆栈中的;debug时,查看堆栈可以知道函数的调用顺序;函数调用时传递参数,事实上是把参数压入堆栈,听起来,堆栈象一个大杂烩。那么,堆栈(Stack)
到底是如何工作的呢? 本文将详解C/C++堆栈的工作机制。阅读时请注意以下几点:
而自己定义的堆栈。
从一些基本的知识和概念开始
(这和自定义的堆栈从低地址向高地址扩展不同),如下图所示:
,本文中,你只需要把EBP和ESP理解成2个指针就可以了。ESP寄存器总是指向堆栈的栈顶,执行PUSH命令向堆栈压入数据时,ESP减4,然后把数据拷贝到ESP指向的地址;执行POP命令时,首先把ESP指向的数据拷贝到内存地址/寄存器中,然后ESP加4。EBP寄存器是用于访问堆栈中的数据的,它指向堆栈中间的某个位置(具体位置后文会具体讲解),函数的参数地址比EBP的值高,而函数的局部变量地址比EBP的值低,因此参数或局部变量总是通过EBP加减一定的偏移地址来访问的,比如,要访问函数的第一个参数为EBP+8。
开始讨论堆栈是如何工作的
。参数入栈的顺序是由函数的调用约定(Calling Convention)决定的,我们将在后面一个专门的章节来讲解调用约定。一般来说,参数都是从右往左入栈的,因此,b=4先压入堆栈,a=3后压入,如图:
函数被调用时,会自动把下一条指令的地址压入堆栈,函数结束时,从堆栈读取这个地址,就可以跳转到该指令执行了。如果当前"call foo"指令的地址是0×,由于call指令占5个字节,那么下一个指令的地址为0××将被压入堆栈:
,用来访问main函数的参数和局部变量的,因此需要将它暂存在堆栈中,在foo函数退出时恢复。同时,给EBP赋于新值。
)。因此,通过EBP很容易查找函数是被谁调用的或者访问函数的参数(或局部变量)。
比如在foo函数中有ESP=ESP-0x00E4,(根据兄在其他编译环境上的测试,也可能使用push命令分配地址,本质上并没有差别,特此说明)如图所示:
(据我观察,总是间隔8个字节)如下图所示:
上一节中,一个完整的堆栈帧已经建立起来,现在函数可以开始正式执行代码了。本节我们对堆栈的特性进行分析,有助于了解函数与堆栈帧的依赖关系。
一个完整的堆栈帧建立起来后,在函数执行的整个生命周期中,它的结构和大小都是保持不变的;不论函数在什么时候被谁调用,它对应的堆栈帧的结构也是一定的。
例如在foo函数中调用foo1函数,foo1函数的堆栈帧将在foo函数的堆栈帧下方建立。如下图所示:
而在特定的堆栈帧中,每个参数或局部变量相对于EBP的地址偏移总是固定的。因此函数对参数和局部变量的的访问是通过EBP加上某个偏移量来访问的。比如,在foo函数中,EBP+8为第一个参数的地址,EBP-8为第一个局部变量的地址。
这个特性有什么用呢,我们知道 EBP+4地址存储了函数的返回地址,通过该地址我们可以知道当前函数的上一级函数(通过在符号文件中查找距该函数返回地址最近的函数地址,该函数即当前函数的上一级函数),以此类推,我们就可以知道当前线程整个的函数调用顺序。事实上,调试器正是这么做的,这也就是为什么调试时我们查看函数调用顺序时总是说“查看堆栈”了。
,由于caller是不知道callee内部是如何执行的,因此caller需要从 callee的函数声明就可以知道应该从什么地方取得返回值。同样的,callee不能随便把返回值放在某个寄存器或者内存中而指望Caller能够正确地获得的,它应该根据函数的声明,按照“约定”把返回值放在正确的”地方“。下面我们来讲解这个“约定”:
1)首先,如果返回值等于4字节,函数将把返回值赋予EAX寄存器,通过EAX寄存器返回。例如返回值是字节、字、双字、布尔型、指针等类型,都通过EAX寄存器返回。
,通过EAX和EDX寄存器返回,EDX存储高位4字节,EAX存储低位4字节。例如返回值类型为__int64或者8字节的结构体通过EAX和EDX返回。
,通过浮点寄存器返回。
未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区—常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
二、例子程序
这是一个前辈写的,非常详细
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
char s[] = ”abc”; 栈
char *p2; 栈
char *p3 = ”123456″; 在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, ”123456″); 放在常量区,编译器可能会将它与p3所指向的”123456″优化成一个地方。
二、堆和栈的理论知识
2.1申请方式
由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
需要程序员自己申请,并指明大小,在c中malloc函数
如p1 = (char *)malloc(10);
在C++中用new运算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在栈中的。
申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
)(英文)。
(英文)。)单一全局锁本质上是用来保护堆数据结构,防止跨多线程的随机存取。若堆操作太频繁,单一全局锁会对性能有不利的影响。
我在学习对象的生存方式的时候见到一种是在堆栈(stack)之中,如下
还有一种是在堆(heap)中
pobject=new
CObject();
&&&&推荐文章:
【上篇】【下篇】2991人阅读
Linux c(43)
今天看代码,定义了一个结构体
typedef struct {
&&& int char[6*1024];
//定义一个指针
ss_t *sTmp = NULL;
sTmp = malloc(sizeof(ss_t));
&我的第一反应是,怎么可以定义这么大数据,容易把栈搞死(理由:数组保存在栈空间)。
哎...忘了是由malloc产生的,根本就是生成在堆上。
但是这样结构体定义变量时就会容易出现栈资源专用严重问题,如下:
这样一个变量就占用了6K多栈资源,就不合理了。定义改为如下
typedef struct {
&&& int char* buf
定义变量 ss_t &再使用malloc申请 buf 就更为合理。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:73801次
积分:1349
积分:1349
排名:千里之外
原创:55篇
转载:51篇
(2)(11)(2)(2)(1)(5)(5)(2)(1)(2)(2)(1)(1)(8)(3)(2)(1)(4)(1)(1)(3)(1)(4)(5)(4)(3)(4)(12)(2)(11)

我要回帖

更多关于 数组 堆栈 的文章

 

随机推荐