C++ 常量存储在何处以及如何存储?

C++ 常量存储在何处以及如何存储?,c++,memory,constants,C++,Memory,Constants,我从中阅读了这个问题,也从中阅读了相关问题,但我不明白这背后的确切原因:- #include <iostream> using namespace std; int main() { //const int *p1 = (int*) &(5); //error C2101: '&' on constant //cout << *p1; const int five = 5;

我从中阅读了这个问题,也从中阅读了相关问题,但我不明白这背后的确切原因:-

#include <iostream>

    using namespace std;

    int main()
    {
        //const int *p1 = (int*) &(5);  //error C2101: '&' on constant
        //cout << *p1;

        const int five = 5;
        const int *p2 = &(five);
        cout << *p2 << endl;

        char *chPtr = (char*) &("abcde");
        for (int i=0; i<4; i++) cout << *(chPtr+i);
        cout << endl;
        return 0;
    }
#包括
使用名称空间std;
int main()
{
//常量int*p1=(int*)&(5);//错误C2101:“&”在常量上

//cout您不能获取文本的地址(例如,
&(5)
),因为文本没有“存储”在任何地方-它实际上是在汇编指令中写入的。根据平台的不同,您将得到不同的指令,但MIPS64添加示例如下所示:

DADDUI R1, R1, #5
尝试获取立即数的地址是没有意义的,因为它不存在于(数据)内存中,但实际上是指令的一部分

如果您声明了一个
常量int i=5
,并且不需要它的地址,编译器可以(而且可能会)将其转换为一个文本,并将
5
放入相应的汇编指令中。一旦您尝试获取
i
的地址,编译器将发现它不再能够这样做,并将其放入内存中。如果您只是尝试获取一个文本的地址,则不会出现这种情况,因为您尚未向编译器发出指示呃,它需要为一个变量分配空间(当您声明一个
常量int i
时,它会在第一次传递时分配空间,然后会确定它不再需要它-它不会以相反的方式工作)


字符串常量存储在数据内存的静态部分,这就是为什么您可以获取它们的地址。

下面是一个示例,以
常量int的地址为例,演示(至少在我的机器上的gcc中)它存储为局部(而非全局静态)变量

#include <iostream>

const int *func() {
    const int five = 5;
    const int *p = &(five);
    std::cout << *p << '\n';
    return p;
}

// function to overwrite stack values left by earlier function call
int func2(int n, int x) {
    for (int i = 0; i < x; ++i)
        n *= 2;
    return n;
}

int main() {
    const int *p = func();
    std::cout << func2(2, 10) << '\n';
    std::cout << *p << '\n';
    return 0;
}
“依情况而定”可能不是一个令人满意的答案,但它是正确的答案。如果需要,编译器将在堆栈中存储一些常量变量(例如,如果您获取它的地址)。然而,“constexpr”的概念一直存在编译器中的变量,即使我们并不总是有直接调用它的机制:如果一个表达式可以在编译时计算,那么我们可以在编译时计算它,而不是在运行时计算它。如果我们可以在编译时计算它,并且我们从不做任何要求它不同的事情,那么我们可以将其全部删除,并将其转换为文字,这将是指令的一部分

以以下代码为例:

int main(int argc, char** argv)
{
  const int a = 2;
  const int b = 3;
  const int c = a+b;

  volatile int d = 6;
  volatile int e = c+d;

  std::cout << e << std::endl;
  return 0;
}
因此,我们可以看到a被初始化为堆栈上的实际内存空间(我可以告诉cuz rsp).但是等等…c依赖于a,但每当我使用c时,它仍然是一个文本5!这里发生了什么?编译器知道a需要位于内存位置,因为它的使用方式。但是,它知道变量的值永远不是2,所以每当我以不需要内存的方式使用它时,我可以将它用作文本2。Which表示第37行中的a与第43行中的a不同

那么常量变量存储在哪里?它们存储在需要存储的地方。疯狂


(顺便说一句,这些都是用g++-g-O2编译的,不同的编译器/标志将以不同的方式对其进行优化,这主要说明了编译器可以做什么,唯一的保证是您的代码将正确运行。)

@user3284107嘿,我在我的问题中提到了这个网站:)你的问题在这里没有得到回答吗?:p啊,我的错。但是根据他们的回答,也许一本书才是你真正的答案:)@VikasVerma好吧,我想这很公平。你可以更明确地说你逐字引用了这个问题。@user3284107我不明白其中的原因这就是为什么我在这里问我,我想在这里我可以找到更好的理由,但他确实采用了
常量int
的地址,这就排除了将该值用作立即汇编操作数的可能性。相反,它存储为一个普通的局部变量,并且简单地防止修改。他可以采用常量int I=5的地址。你不能采用5b的地址但您可以引用5:
const int&f=5;
,在某些情况下,短字符串也不会存储在任何位置。4个字符的“abcd”不一定需要存储为数组。有些CPU可能需要存储值5,因为它们没有立即值指令。@ooga实际上,许多编译器在这种情况下都会这样做。当您按值使用
const int
时,它将使用文本来保存对内存的命中,并将其存储在内存中,以便它可以被指针引用。
int main(int argc, char** argv)
{
  const int a = 2;
  const int b = 3;
  const int c = a+b;

  volatile int d = 6;
  volatile int e = c+d;

  std::cout << e << std::endl;
  return 0;
}
    37    const int a = 2;
    38    const int b = 3;
    39    const int c = a+b;
    40
    41    volatile int d = 6;
0x400949  <+0x0009>         movl   $0x6,0x8(%rsp)
    42    volatile int e = c+d;
0x400951  <+0x0011>         mov    0x8(%rsp),%eax
0x400955  <+0x0015>         add    $0x5,%eax
0x400958  <+0x0018>         mov    %eax,0xc(%rsp)
    43
    44    std::cout << e << std::endl;
0x400944  <+0x0004>         mov    $0x601060,%edi
0x40095c  <+0x001c>         mov    0xc(%rsp),%esi
0x400960  <+0x0020>         callq  0x4008d0 <_ZNSolsEi@plt>
    45    return 0;
    46  }
int main(int argc, char** argv)
{
  const int a = 2;
  const int b = 3;
  const int c = a+b;

  volatile int d = 6;
  volatile int e = c+d;
  volatile int* f = (int*)&a;
  volatile int g = *f;

  std::cout << e << std::endl;
  std::cout << g << std::endl;
  return 0;
}


    37        const int a = 2;
0x400955  <+0x0015>         movl   $0x2,(%rsp)
    38        const int b = 3;
    39        const int c = a+b;
    40
    41        volatile int d = 6;
0x400949  <+0x0009>         movl   $0x6,0x4(%rsp)
    42        volatile int e = c+d;
0x400951  <+0x0011>         mov    0x4(%rsp),%eax
0x40095c  <+0x001c>         add    $0x5,%eax
0x40095f  <+0x001f>         mov    %eax,0x8(%rsp)
    43        volatile int* f = (int*)&a;
    44        volatile int g = *f;
0x400963  <+0x0023>         mov    (%rsp),%eax
0x400966  <+0x0026>         mov    %eax,0xc(%rsp)
    45
    46        std::cout << e << std::endl;
0x400944  <+0x0004>         mov    $0x601060,%edi
0x40096a  <+0x002a>         mov    0x8(%rsp),%esi
0x40096e  <+0x002e>         callq  0x4008d0 <_ZNSolsEi@plt>
    47        std::cout << g << std::endl;
0x40097b  <+0x003b>         mov    0xc(%rsp),%esi
0x40097f  <+0x003f>         mov    $0x601060,%edi
0x400984  <+0x0044>         callq  0x4008d0 <_ZNSolsEi@plt>
    48        return 0;