gpt4 book ai didi

pointers - 地址常量表达式

转载 作者:行者123 更新时间:2023-12-04 00:41:57 25 4
gpt4 key购买 nike

我在阅读“C++ 编程语言第 4 版”一书时正在研究地址常量表达式。它有一小段描述地址常量表达式:

The address of a statically allocated object, such as a global variable, is a constant. However, its value is assigned by the linker, rather than the compiler, so the compiler cannot know the value of such an address constant. That limits the range of constant expressions of pointer and reference type. For example:

constexpr const char* p1 = "asdf";
constexpr const char* p2 = p1; //OK
constexpr const char* p2 = p1+2; //error: the compiler does not know the value of p1
constexpr char c = p1[2]; //OK, c=='d'; the compiler knows the value pointed to by p1

我有两个问题。

  1. 这一条相当简单 - 因为编译器不知道静态对象的地址,那么它如何在编译期间评估第二条语句?毕竟,编译器不知道 p1+2 的值这一事实意味着 p1 首先必须是未知的,对吧?不过,打开所有严格标志的 g++ 4.8.1 接受所有这些语句。

  2. this topic 中所示:

static constexpr int N = 3;
int main()
{
constexpr const int *NP = &N;
return 0;
}

Here, NP is declared as an address constant-expression, i.e. an pointer that is itself a constant expression. (This is possible when the address is generated by applying the address operator to a static/global constant expression.)

如果我们将 N 声明为简单的 const 而没有 constexpr,这也可以工作。但是,必须使用 constexpr 显式声明 p1 才能使 p2 成为有效语句。否则我们得到:

error: the value of ‘p1’ is not usable in a constant expression

这是为什么呢?据我所知,"asdf" 属于 const char[]

最佳答案

N3485 包含关于“地址常量表达式”

An address constant expression is a prvalue core constant expression (after conversions as required by the context) of ... pointer type that evaluates to the address of an object with static storage duration ....

字符串字面量的第三个字符对象就是这样一个对象(见2.14.5的细化),不亚于第一个。

请注意,这里没有使用变量,而是对象(因此我们可以访问数组元素以及类成员以获得地址常量表达式,前提是数组或类对象具有静态存储持续时间,并且访问不会违反核心常量表达式的规则。

从技术上讲,链接器将执行目标文件中的重定位:

constexpr const char *x = "hello";
extern constexpr const char *y = x + 2;

我们将把它编译成一个目标文件,看看它做了什么

[js@HOST1 cpp]$ clang++ -std=c++11 -c clangtest.cpp
[js@HOST1 cpp]$ objdump --reloc ./clangtest.o

./clangtest.o: file format elf32-i386

RELOCATION RECORDS FOR [.rodata]:
OFFSET TYPE VALUE
00000000 R_386_32 .L.str


[js@HOST1 cpp]$ objdump -s -j .rodata ./clangtest.o

./clangtest.o: file format elf32-i386

Contents of section .rodata:
0000 02000000 ....
[js@HOST1 cpp]$

链接器将获取该部分中已有的值,并将其添加到重定位的“VALUE”属性引用的符号值(这意味着它在符号表中的地址)(在我们的如果我们添加了 2 ,那么 Clang/LLVM 在该部分中硬编码了一个 2

However, p1 has to be declared explicitly using constexpr in order to p2 be a valid statement.

那是因为你依赖它的值而不是它的地址来保持不变。通常(见下文)您必须事先将其标记为 constexpr,以便此时的编译器可以验证任何以后的读取访问肯定可以依赖于获取常量。您可能希望按如下方式更改它并查看它的工作情况(我认为,因为对于整数和枚举类型的初始化 const 对象存在特殊情况,您甚至可以读取下面的 p1 数组constexpr 上下文,即使它没有被标记为 constexpr 。但是我的 clang 似乎拒绝了它)

const char p1[] = "asdf";
constexpr const char *x = p1 + 2; // OK!
constexpr char y = p1[2]; // OK!

关于pointers - 地址常量表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17658446/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com