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;