搬砖:程序中的局部变量是编译时候分配地址的还是运行时分配的呢

探讨程序中的局部变量是在编译时还是运行时分配地址的问题,分析局部变量在栈中的分配机制,以及函数调用过程中栈帧的变化和局部变量的访问方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

太无耻了吧,都没给别人分,,,,

 

程序中的局部变量是编译时候分配地址的还是运行时分配的呢? [问题点数:40分]

https://bbs.youkuaiyun.com/topics/350012472

borefo

Bbs2

结帖率 90%

程序中的局部变量是编译时候分配地址的还是运行时分配的呢?

按照我的理解,局部变量是在栈中分配的,应该是在运行时分配地址的,不知道对不对?

栈是一种先进后出的数据结构,局部变量是在栈中分配的,那么后面的代码要引用这个变量时,前面的变量是不是全部要弹出栈才能引用这个变量呢?谢谢

0 2010-08-26 11:10:01

回复数 23 只看楼主 引用 举报 楼主

pengzhixi

Bbs9

BlankBlankBlank

那如果函数有几个参数要压栈怎么办呢?通过基址加偏移量访问就是了。

0 2010-08-26 11:11:38

只看TA 引用 举报 #1    得分 0

c++中为什么有些变量在编译时就由编译器分配了内存空间,还没有运行怎么会占用内存呢 还没有运行怎么会占用内存呢?!(这一点还要怀疑吗!?) 所谓在编译期间分配空间指的是静态分配空间(相对于用new动态申请空间),如全局变量或静态变量(包括一些复杂类型的常量),它们所需要的空间大小可以明确计算出来,并且不会再改变,因此它们可以直接存放在可执行文件的特定的节里(而且包含初始化的值),程序运行时也是直接将这个节加载到特定的段中,不必在程序运行期间用额外的代码来产生这些变量。   其实...

Bbs5

运行时分配;

在同一个函数中,不用弹出栈;

在函数调用的时候,调用前,参数压栈,调用完成,参数出栈(依据函数类型不同,可能是函数本身恢复栈,可能是调用方恢复栈)。

0 2010-08-26 11:37:03

只看TA 引用 举报 #2    得分 0

局部变量在编译时就确定地址吗 http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=3773446

aozhi

Bbs5

函数内部应该是用的同一堆栈段,基址寄存器内容不变,可以直接靠偏移地址访问。

0 2010-08-26 11:47:05

只看TA 引用 举报 #3    得分 0

书上说,编译时,变量的内存地址就确定了,可是内存是动态分配的呀,为什么说编译时能够确定内存地址,永不变化呢? 书上说,编译时,变量的内存地址就确定了,可是内存是动态分配的呀,为什么说编译时能够确定内存地址,永不变化呢? 书上原话是: 如果在程序中定义了一个变量,在编译时系统就会给这个变量分配内存单元,并根据程

borefo

Bbs2

引用 2 楼 lazy_2010 的回复:

运行时分配;

在同一个函数中,不用弹出栈;

在函数调用的时候,调用前,参数压栈,调用完成,参数出栈(依据函数类型不同,可能是函数本身恢复栈,可能是调用方恢复栈)。



如果是运行时分配的话,我把可执行文件反汇编,里面也有个偏移量,这个偏移量和运行时分配的地址有什么联系呢?

C/C++ code?

1

2

3

4

5

6

7

8

9

int main()

{

        int i = 0;

        int c = 1;

 

        i = i + c;

 

        return 0;

}

 

Assembly code?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

00000000004004e4 <main>:

  4004e4:       55                      push   %rbp

  4004e5:       48 89 e5                mov    %rsp,%rbp

  4004e8:       c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%rbp)

  4004ef:       c7 45 fc 01 00 00 00    movl   $0x1,-0x4(%rbp)

  4004f6:       8b 45 fc                mov    -0x4(%rbp),%eax

  4004f9:       01 45 f8                add    %eax,-0x8(%rbp)

  4004fc:       b8 00 00 00 00          mov    $0x0,%eax

  400501:       c9                      leaveq

  400502:       c3                      retq

  400503:       90                      nop

  400504:       90                      nop

  400505:       90                      nop

  400506:       90                      nop

  400507:       90                      nop

  400508:       90                      nop

  400509:       90                      nop

  40050a:       90                      nop

  40050b:       90                      nop

  40050c:       90                      nop

  40050d:       90                      nop

  40050e:       90                      nop

  40050f:       90                      nop

0 2010-08-26 11:49:10

只看TA 引用 举报 #4    得分 0

Java内存分配 JVM内存分配简要说明

borefo

Bbs2

我想问的是,
1)在程序编译的时候,编译程序会建立一张符号表,存放每个名字对应的地址,这个地方是偏移地址还是真实地址呢?

2)一般程序先定义的变量先压栈,但从汇编可以看出i是存在栈顶,这是为什么呢?

0 2010-08-26 11:57:52

只看TA 引用 举报 #5    得分 0

svtanto

Bbs3

1、一个程序的栈是固定大小的,至少你没有明确指定的情况下,所以程序编译后大小就定了,你修改代码把某个函数的局部变量从1个增加到100个,程序的字节数没有变化。
2、每一个局部变量在内存的次序是在编译的时候就确定了,但是在内存的位置和程序运行有关,具体的说:
   每个程序只有一个堆栈,假设如下函数:
void fun() {
    char a;
    short b;
    int c;
    long d;
    float b;
    double c;
    ...   
}
局部变量的内存占用的相对顺序是不变的,但是第一个局部变量的地址是在运行时候决定的。

0 2010-08-26 12:33:02

只看TA 引用 举报 #6    得分 0

jvm编译时自动生成的局部变量 每个方法调用都会产生一个新的栈帧,每个java栈帧存储三部分内容: 1、局部变量区,主要是存储方法参数和方法内部声明局部变量。jvm编译成的class文件中,Code属性的max_locals指出一共有多少个局部变量。局部变量的详细信息都在code属性的local attribute table有列出。 2、操作数栈,压栈出栈就是操作的这个栈。一般情况下,这个栈的最大深度都不是很大,可以随便找...

svtanto

Bbs3

堆栈中的变量是靠修改栈指针来访问的,并不需要弹出堆栈就可以访问

0 2010-08-26 12:34:50

只看TA 引用 举报 #7    得分 0

局部变量什么时候分配内存 以前在学习的时候看到过一句话, “ 栈区(stack)— 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。程序结束时由编译器自动释放 ” 就一直以为局部变量内存是由编译器分配,也没多想怎么分配。 今天被别人问到 “程序执行的过程中编译器怎么还能参与内存分配” 一下就傻眼了,网上查了下,这句话的意思应该是  “ 编译器在编译的过程中,

ForestDB

Bbs8

BlankBlank

程序中的局部变量是编译时候分配地址的还是运行时分配的呢?
按照我的理解,局部变量是在栈中分配的,应该是在运行时分配地址的,不知道对不对?
正解
栈是一种先进后出的数据结构,局部变量是在栈中分配的,那么后面的代码要引用这个变量时,前面的变量是不是全部要弹出栈才能引用这个变量呢?谢谢
不用,栈顶由寄存器标识,局部变量通过栈顶加偏移表示。
如果是运行时分配的话,我把可执行文件反汇编,里面也有个偏移量,这个偏移量和运行时分配的地址有什么联系呢?
有没有发现,偏移量是和变量对应的,但都是和rbp相对来的,每次调用函数的时候,rbp可能是不一样的,所以最后的地址是会不一样的,但是相对于rbp的位置总是固定的。
我想问的是,
1)在程序编译的时候,编译程序会建立一张符号表,存放每个名字对应的地址,这个地方是偏移地址还是真实地址呢?
就local variable来讲,是对于栈顶的偏移。
2)一般程序先定义的变量先压栈,但从汇编可以看出i是存在栈顶,这是为什么呢?
这个是编译器的实现,这里是我的环境的情形,比较像你所期待的。

Assembly code?

1

2

3

4

5

6

7

movl    $0, -4(%rbp)

movl    $1, -8(%rbp)

movl    -8(%rbp), %eax

addl    %eax, -4(%rbp)

movl    $0, %eax

leave

ret

 

0 2010-08-26 12:58:45

只看TA 引用 举报 #8    得分 0

Java学习篇之--用纯Java的JDBC驱动程序实现与数据库连接 用纯Java的JDBC驱动程序实现与数据库连接 最近在研究JAVA中数据库的连接,将知识整理一下分享给大家: Java程序可以用纯Java的JDBC驱动程序实现与数据库连接。这种方法应用较广泛,但是需要下载相应的驱动程序包,因为不同的数据库的连接代码可能不同,连接不同的数据库,加载的驱动程序也可能不同。本文将以MySQL数据库为例来讲解连接数据库的过程。 首先下载驱动程序: mysql-connector-java-5.0.8-bin.jar 然后添加驱动

ForestDB

Bbs8

BlankBlank

推荐看深入理解计算机系统,或者计算机组成原理之类的书。

0 2010-08-26 13:00:34

只看TA 引用 举报 #9    得分 0

请教:变量到底是在编译的时候初始化的,还是在运行的时候初始化的? 变量到底是在编译的时候初始化的,还是在运行的时候初始化的? 如下函数:居然调用两次打印出来的值分别是1和2,非常不好理解 如果按照C PRIMER PLUS说的这样的变量是在编译的时候初始化的, 实在

borefo

Bbs2

引用 7 楼 svtanto 的回复:

栈是一种先进后出的数据结构,局部变量是在栈中分配的,那么后面的代码要引用这个变量时,前面的变量是不是全部要弹出栈才能引用这个变量呢?谢谢
不用,栈顶由寄存器标识,局部变量通过栈顶加偏移表示。



谢谢你的详细解答

红色部分是不是有误?应该是栈底吧?

0 2010-08-26 13:16:10

只看TA 引用 举报 #10    得分 0

Bbs5

对于函数调用的情况,栈顶指针数值 < 栈底指针数值;

最后一次压栈之后的地方是栈顶,所以 8# 说栈顶是没错的。

0 2010-08-27 13:58:11

只看TA 引用 举报 #12    得分 0

编译原理习题(含答案)——15运行存储分配——哈工大陈鄞配套版本 运行存储分配1 在目标代码生成阶段,符号表用于()。A. 目标代码生成B. 语义检查C. 语法检查D. 地址分配 2 PASCAL语言中过程声明的局部变量地址分配在( )。A. 调用者的数据区中B. 被调用者的数据区中C. 主程序的数据区中D. 公共数据区中 3 编译方法中,动态存储分配的含义是()。A. 在编译阶段为源程序中的量进行分配B. 在编译阶段为源程序中的量进行分配,运行时可动态调整C....

wjb_yd

Bbs5

lz需要补习一下基础知识。
一个工程编译完,只是生成了1个可执行文件,里面含有2进制的代码和需要初始化的数据等等,如果你不运行它,它是不会占内存的,只占硬盘空间而已。

而加载器将这个可执行文件加载到内存后,会为对应的进程分配地址空间,其中一部分就是栈,也就是所有函数运行时局部变量所在的位置。而可执行文件中的代码,随着函数调用深度的增加,会一点点地从高地址到低地址使用栈的空间,如果使用的栈空间太大,程序会直接崩掉。

而lz所说的运行时分配,也就是代码运行到那里了,在栈上减一段地址(也就是减ESP的值,ESP以上的地址我们认为都是已经被使用的),用来给新的局部变量使用了。

0 2010-08-27 13:59:21

只看TA 引用 举报 #13    得分 0

C/C++程序编译时和运行时内存区域分配 c程序内存分配区域问题。记得以前学《Unix高级环境编程》时书中有提到c程序内存分配问题。然后有次面试时,问到这个问题我根据书上的内容来回答的,面试官却说回答的对了一半,当时很纳闷怎么会对了一半呢。下面来解释下。         先来说下c程序编译内存分配:         1.栈区(stack):存放局部变量和参数,申请和释放都由编译器自动完成。         2.堆区(he

wjb_yd

Bbs5

我估计lz所说的编译时,指的是栈。而运行时,指的是堆。

0 2010-08-27 14:00:58

只看TA 引用 举报 #14    得分 0

变量声明有没有分配内存? Q1: int i 这个有没有分配内存呢? int *p 呢? 具体是在栈空间还是在堆空间里分配内存呢?   A1: int i; int *p; 这两个都在栈区分配了内存空间 但是p指向的地址为野地址,不可直接拿来使用 即p指向的空间没有分配   Q2:在Java中定义数组时必须分配内存,这句话是错的还是对的呢   A2: Java

csucdl

Bbs5

引用楼主 borefo 的回复:

程序中的局部变量是编译时候分配地址的还是运行时分配的呢?

按照我的理解,局部变量是在栈中分配的,应该是在运行时分配地址的,不知道对不对?

栈是一种先进后出的数据结构,局部变量是在栈中分配的,那么后面的代码要引用这个变量时,前面的变量是不是全部要弹出栈才能引用这个变量呢?谢谢



地址指的是内存地址, 所以从这个意义上来说, 任何变量肯定都是在运行时分配地址的。
不过编译器在编译的时候给全局, 静态, stack变量分配了相对于段基址的偏移量地址

0 2010-08-27 14:05:12

只看TA 引用 举报 #15    得分 0

waigua0

Bbs1

在编译的语义分析阶段会给出每一个变量的一个相对地址,全局变量的是基于静态数据区基址的偏移量,而局部变量是相对于其运行时所对应活动记录基址的相对地址。
程序的目标代码和全局变量都是在编译时存入静态数据区的。局部变量是程序运行时动态地分配地址的。这个存储的分配是以栈的形式组织的。当某个函数运行时,为其局部数据建立活动记录,并将其入栈。
如果程序设计语言不允许函数的嵌套定义(例如C语言)函数体里肯定是对本函数中的局部变量进行引用或者引用静态数据区的全局变量。要是引用的是本函数中的局部变量,则该变量就在栈顶活动记录中(栈顶永远是正在运行的函数的活动记录)。其偏移量已经在语义分析时确定了。若引用的是全局变量,则直接去静态数据区查找。
如果程序设计语言允许函数的嵌套定义(例如Pascal语言),内层函数还可能引用外层函数中的变量。这时就要根据活动记录里存放的过程层次链来有内层函数向外层函数逐层去查找了。

但愿对你有助~

0 2011-06-02 20:27:58

只看TA 引用 举报 #16    得分 0

java定义变量的时候分配内存的过程 堆栈 静态存储区域 一个由C/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区(heap)— 由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。 3、全局区(静态区)(static)— 全局变量和静...

AnYidan

Bbs7

compiler 中的 stack 与你理解的有所不同

虽然它只能 push/pop 最顶层的元素,但它可以访问(读写)当前函数可见的任何变量,这是通过 stack frame 实现的

很多书中对此有详细的介绍

0 2011-06-03 10:26:28

只看TA 引用 举报 #17    得分 0

游戏辅助原理与制作第三课--------基址与动态地址     在前面一节课我们已经实现了游戏的阳光值修改,并且也写出了程序,现在我们重新打开游戏,再启动我们写的程序,并进行修改:我们发现,修改失败!这是为什么呢?难道我们的阳光的内存地址发生了变化?我们打开工具,再次进行寻找:我们重新寻找后,发现现在的阳光内存地址为:171A2578,而我们之前所找到的地址是:20194DC8。看来我们的阳光地址已经发生了变化,那这到底是为什么呢?    这里,一些C...

naturemickey

Bbs5

局部变量是在编译时分配地址(可以直接分配寄存器)的,
在加载程序枵运行时库的时候,操作系统会以当前的加载地址做偏移量修改所有静态地址。

参考资料:《Reversing:逆向工程揭密》

0 2011-06-03 10:59:51

只看TA 引用 举报 #18    得分 0

java程序运行时如何分配内存 Java 虚拟机(JVM)是可运行Java代码的假想计算机。只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何Java代码能够在该系统上运行。本文首先简要介绍从Java文件的编译到最终执行的过程,随后对JVM规格描述作一说明。      一.Java源文件的编译、下载、解释和执行   Java应用程序的开发周期包括编译、下载、解释和执行几个部分。Java编译程序将Ja

neolyaoo

Bbs3

参考资料:《Reversing:逆向工程揭密》

0 2011-06-03 12:41:30

只看TA 引用 举报 #19    得分 0

C++ 关于书上说的“编译的时候分配内存” 1、所谓在编译期间分配空间指的是静态分配空间(相对于用new动态申请空间),如全局变量或静态变量(包括一些复杂类型的常量),它们所需要的空间大小可以 明确计算出来,并且不会再改变,因此它们可以直接存放在可执行文件的特定的节里(而且包含初始化的值),程序运行时也是直接将这个节加载到特定的段中,不 必在程序运行期间用额外的代码来产生这些变量。  其实在运行期间再看“变量”这个概念就不再具备编译期间那

遥望未来_cheerup

Bbs2

来学习的!!

0 2011-06-03 16:15:21

只看TA 引用 举报 #20    得分 0

linux_qt

Bbs3

13楼也该好好看看书了

0 2011-12-13 15:40:27

只看TA 引用 举报 #22    得分 0

c语言局部变量的内存地址分配顺序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值