60

我想知道常量变量存储在哪里。它和全局变量在同一个内存区域吗?还是在堆栈上?

4

14 回答 14

47

它们的存储方式是一个实现细节(取决于编译器)。

例如,在 GCC 编译器中,在大多数机器上,只读变量、常量和跳转表都放在文本部分中。

于 2009-10-16T06:51:31.480 回答
37

根据特定处理器遵循的数据分段,我们有五个分段:

  1. 代码段 - 仅存储代码、ROM
  2. BSS(或由符号开始的块) 数据段 - 存储初始化的全局和静态变量
  3. 堆栈段 - 存储所有局部变量和有关函数返回地址等的其他信息
  4. 堆段 - 所有动态分配都发生在这里
  5. 数据 BSS(或由符号开始的块)段 - 存储未初始化的全局和静态变量

请注意,数据段和 BSS 段之间的区别在于前者存储初始化的全局和静态变量,而后者存储未初始化的变量。

现在,我为什么要谈论数据分段,而我必须只是告诉常量变量存储在哪里……这是有原因的……

每个段都有一个写保护区域,其中存储了所有常量。

例如:

  • 如果我有一个局部变量 const int,则它存储在堆栈段的写保护区域中。
  • 如果我有一个初始化为 const var 的全局变量,那么它将存储在数据段中。
  • 如果我有一个未初始化的 const var,那么它将存储在 BSS 段中......

总而言之,“const”只是一个数据限定符,这意味着首先编译器必须决定变量必须存储在哪个段,然后如果变量是 const,那么它有资格存储在的写保护区域那个特定的部分。

于 2009-11-05T15:22:06.530 回答
12

考虑代码:

const int i = 0;
static const int k = 99;

int function(void)
{
    const int j = 37;
    totherfunc(&j);
    totherfunc(&i);
  //totherfunc(&k);
    return(j+3);
}

一般情况下,i可以存储在文本段中(它是一个具有固定值的只读变量)。如果它不在文本段中,它将存储在全局变量旁边。鉴于它被初始化为零,它可能位于“bss”部分(通常分配零变量的位置)或“数据”部分(通常分配初始化变量的位置)。

如果编译器确信它k是未使用的(它可能是因为它是单个文件的本地文件),它可能根本不会出现在目标代码中。如果对该totherfunc()引用的调用k没有被注释掉,那么k就必须在某处分配一个地址——它可能与i.

常量(如果它是常量,它仍然是变量吗?)j很可能会出现在传统 C 实现的堆栈上。(如果您在 comp.std.c 新闻组中询问,有人会提到标准并没有说自动变量出现在堆栈上;幸运的是,SO 不是 comp.std.c!)

请注意,我强制变量出现是因为我通过引用传递了它们 - 大概是一个函数,该函数需要一个指向常量整数的指针。如果地址从未被占用,那么j可以k完全从代码中优化。要删除i,编译器必须知道整个程序的所有源代码 - 它可以在其他翻译单元(源文件)中访问,因此不能轻易删除。如果程序沉迷于共享库的动态加载,那就更不用说了——其中一个库可能依赖于该全局变量。

(风格上——变量应该有更长ij更有意义的名字;这只是一个例子!)

于 2009-10-16T07:11:48.023 回答
5

取决于您的编译器、系统功能、编译时的配置。

gcc .text除非另有说明,否则只读常量放在节上。

于 2009-10-16T06:55:27.253 回答
2

通常它们存储在只读数据部分(而全局变量部分具有写权限)。因此,尝试通过获取其地址来修改常量可能会导致访问冲突,即 segfault。

但这实际上取决于您的硬件、操作系统和编译器。

于 2009-10-16T06:52:25.970 回答
2

当然不是,因为

1)bss 段存储了非初始化变量,显然存在另一种类型。

       (I) large static and global and non constants and non initilaized variables it stored .BSS section.

       (II) second thing small static and global variables and non constants and non initilaized variables stored in .SBSS section this included in .BSS segment.

2)数据段是初始化变量,它有3种类型,

      (I) large static and global and initlaized and non constants variables its stord in .DATA section.
      (II) small static and global and non constant and initilaized variables its stord in .SDATA1 sectiion.
     (III) small static and global and  constant and initilaized OR non initilaized variables its stord in .SDATA2 sectiion.

我上面提到的小型和大型手段取决于编译器,例如小型手段 < 小于 8 字节,大型手段 > 8 字节和相等的值。

但我怀疑局部常数会在哪里出现??????

于 2011-02-03T13:16:46.327 回答
1

这主要是一个有根据的猜测,但我想说常量通常存储在编译程序的实际 CPU 指令中,作为即时数据。换句话说,大多数指令都包含用于从中获取数据的地址的空间,但如果它是一个常量,则该空间可以保存值本身。

于 2009-10-16T06:53:03.810 回答
1

它依赖于编译器,但请注意它甚至可能没有完全存储。因为编译器只需要优化它并将它的值直接添加到使用它的表达式中。

我将此代码添加到程序中并使用 gcc 为 arm cortex m4 编译,检查内存使用情况的差异。

没有const

int someConst[1000] = {0};

在此处输入图像描述

使用const

const int someConst[1000] = {0};

在此处输入图像描述

于 2021-07-30T19:02:34.593 回答
0

全局和常量是两个完全分开的关键字。你可以有一个或另一个,没有或两者都有。

那么,变量在内存中的存储位置取决于配置。阅读一些关于heapstack的内容,这将为您提供一些知识来提出更多(如果可以的话,更好和更具体)的问题。

于 2009-10-16T06:55:55.637 回答
0

一些常量甚至没有被存储。

考虑以下代码:

int x = foo();
x *= 2;

编译器可能会将乘法转换x = x+x;为,因为这样可以减少从内存中加载数字 2 的需要。

于 2009-10-16T07:40:44.727 回答
0

它可能根本不存储。

考虑一些这样的代码:

#import<math.h>//import PI
double toRadian(int degree){
  return degree*PI*2/360.0;
}

这使程序员能够收集正在发生的事情的想法,但是编译器可以通过在编译时评估常量表达式来优化其中的一些,大多数编译器都会这样做,这意味着值 PI 可能不在生成的程序中一点也不。

于 2009-10-16T07:44:18.223 回答
0

就像一个附加的一样,你知道它在链接过程中决定了最终可执行文件的内存布局。还有一个称为 COMMON 的部分,其中放置了来自不同输入文件的公共符号。这个公共部分实际上属于在 .bss 部分下。

于 2015-09-07T12:56:31.537 回答
0

我检查了 x86_64 GNU/Linux 系统。通过取消引用指向“const”变量的指针,可以更改值。我使用了objdump。在文本段中未找到“const”变量。'const' 变量存储在堆栈中。'const' 是“C”中的编译器指令。当遇到更改“const”变量的语句时,编译器会抛出错误。

于 2019-07-16T09:12:21.213 回答
0

这是特定于 Win32 系统的。

在此处输入图像描述

于 2020-10-05T02:01:34.350 回答