我在阅读《C++ 编程语言第四版》一书时正在深入研究地址常量表达式。它有一个简短的段落描述了地址常量表达式:
静态分配对象的地址,例如全局对象
变量,是常数。然而,它的值是由链接器分配的,
而不是编译器,因此编译器无法知道
这样的地址常量。这限制了常数的范围
指针和引用类型的表达式。例如:
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
我有两个问题。
这是相当微不足道的 - 由于编译器不知道静态对象的地址,那么它如何在编译时评估第二条语句?毕竟,编译器不知道的值p1+2
, 暗示p1
首先必须是未知的,对吗?不过,打开所有严格标志的 g++ 4.8.1 接受所有这些语句。
如示例所示这个话题 https://stackoverflow.com/a/14117121/1576085:
static constexpr int N = 3;
int main()
{
constexpr const int *NP = &N;
return 0;
}
这里,NP被声明为地址常量表达式,即
指针本身就是一个常量表达式。 (当
地址是通过将地址运算符应用于
静态/全局常量表达式。)
如果我们声明这也会起作用N
简单地说const
没有constexpr
。然而,p1
必须使用显式声明constexpr
为了p2
是一个有效的陈述。否则我们得到:
错误:“p1”的值在常量表达式中不可用
这是为什么?"asdf"
is of const char[]
据我所知。
N3485包含关于“地址常量表达式”
地址常量表达式是...指针类型的纯右值核心常量表达式(根据上下文需要进行转换后),其计算结果为具有静态存储持续时间的对象的地址...。
字符串文字的第三个字符对象就是这样一个对象(参见2.14.5的详细说明),不小于第一个对象。
请注意,没有使用variable, but object(因此,我们可以访问数组元素以及类成员来获取地址常量表达式,前提是数组或类对象具有静态存储持续时间,并且访问不会违反核心常量表达式的规则)。
从技术上讲,链接器将在目标文件中执行重定位:
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
在部分)。
但是,必须使用 constexpr 显式声明 p1 才能使 p2 成为有效语句。
这是因为您依赖它的值而不是它的地址来保持不变。一般来说(见下文),您必须事先将其标记为 constexpr,以便编译器此时可以验证任何以后的读取访问肯定可以依赖于获取常量。您可能想按如下方式更改它并查看它的工作原理(我认为因为对于整型和枚举类型的初始化 const 对象有一种特殊情况,您甚至可以read从下面p1
constexpr 上下文中的数组,即使没有被标记constexpr
。然而我的 clang 似乎拒绝了它)
const char p1[] = "asdf";
constexpr const char *x = p1 + 2; // OK!
constexpr char y = p1[2]; // OK!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)