首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >局部变量的地址是常量表达式吗?

局部变量的地址是常量表达式吗?
EN

Stack Overflow用户
提问于 2019-04-16 08:12:22
回答 3查看 1.4K关注 0票数 22

在Bjarne Stroustrup的第267页上的书“C++编程语言(第4版)”(第10.4.5节地址常量表达式)中,他使用了一个将局部变量的地址设置为constexpr变量的代码示例。我认为这看起来很奇怪,所以我尝试使用g++版本7.3.0运行该示例,但无法获得相同的结果。下面是他的代码示例(尽管略有删节):

代码语言:javascript
复制
extern char glob;

void f(char loc) {
    constexpr const char* p0 = &glob; // OK: &glob's is a constant
    constexpr const char* p2 = &loc;  // OK: &loc is constant in its scope
}

当我运行这段代码时,我得到:

代码语言:javascript
复制
error: ‘(const char*)(& loc)’ is not a constant expression

g++是否发生了一些我不知道的事情,或者Bjarne的例子中还有更多的东西?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-04-16 08:31:34

早些时候,Bjarne Stroustrup的书"The C++ Programming Language (第4版)“在第267页上的印刷中出现了OP的问题中概述的错误。目前的印刷版和电子版已被“更正”,但引入了另一个错误,稍后将介绍。它现在引用以下代码:

代码语言:javascript
复制
constexpr const char* p1="asdf";

这是可以的,因为"asdf“存储在一个固定的内存位置。在之前的打印中,这本书出现了以下错误:

代码语言:javascript
复制
void f(char loc) {
    constexpr const char* p0 = &glob; // OK: &glob's is a constant
    constexpr const char* p2 = &loc;  // OK: &loc is constant in its scope
}

但是,loc不在固定的内存位置。它在堆栈上,并将根据调用时间的不同而具有不同的位置。

然而,当前的第四版印刷有另一个错误。下面是10.5.4中的代码:

代码语言:javascript
复制
int main() {
    constexpr const char* p1 = "asdf";
    constexpr const char* p2 = p1;      // OK
    constexpr const char* p3 = p1+2;    // error:  the compiler does not know the value of p1
}

这是错误的。编译器/链接器确实知道p1的值,并且可以在链接时确定p1+2的值。它编译得很好。

票数 16
EN

Stack Overflow用户

发布于 2019-04-16 08:47:08

在我的"The C++ Programming Language (第4版)“硬拷贝中提供的第10.4.5节中的示例似乎是不正确的。所以我得出结论,局部变量的地址不是constexpr

该示例在某些pdf版本中似乎已更新,如下所示:

票数 9
EN

Stack Overflow用户

发布于 2019-04-17 16:16:39

这个答案试图通过分析x86-64体系结构的一个示例来澄清为什么局部变量的地址不能为constexpr

考虑下面的玩具函数print_addr(),它显示了它的局部变量local_var的地址,并递归地调用自己n次:

代码语言:javascript
复制
void print_addr(int n) {
   int local_var{};
   std::cout << n << " " << &local_var << '\n';

   if (!n)
      return; // base case

   print_addr(n-1);  // recursive case
}

print_addr(2)的调用在我的x86-64系统上产生了以下输出:

代码语言:javascript
复制
2 0x7ffd89e2cd8c
1 0x7ffd89e2cd5c
0 0x7ffd89e2cd2c

如您所见,每次调用print_addr()时,local_var的相应地址都不同。您还可以看到,函数调用越深,局部变量local_var的地址就越低。这是因为在x86-64平台上堆栈向下增长(即从较高地址到较低地址)。

对于上面的输出,x86-64平台上的call stack将如下所示:

代码语言:javascript
复制
                |     . . .     |
Highest address ----------------- <-- call to print_addr(2) 
                | print_addr(2) |    
                -----------------
                | print_addr(1) |
                -----------------
                | print_addr(0) | <-- base case, end of recursion
Lowest address  ----------------- Top of the stack

上面的每个矩形表示每次调用print_addr()stack frame。每个调用的local_var位于其相应的堆栈框架中。由于每次调用print_addr()local_var都位于自己的(不同)堆栈帧中,因此local_var的地址也不同。

总而言之,由于函数中局部变量的地址对于函数的每次调用都可能不相同(即,每个调用的堆栈帧可能位于内存中的不同位置),因此无法在编译时确定此类变量的地址,因此不能限定为constexpr

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55698844

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档