地址常量表达式

2024-06-18

我在阅读《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

我有两个问题。

  1. 这是相当微不足道的 - 由于编译器不知道静态对象的地址,那么它如何在编译时评估第二条语句?毕竟,编译器不知道的值p1+2, 暗示p1首先必须是未知的,对吗?不过,打开所有严格标志的 g++ 4.8.1 接受所有这些语句。

  2. 如示例所示这个话题 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从下面p1constexpr 上下文中的数组,即使没有被标记constexpr。然而我的 clang 似乎拒绝了它)

const char p1[] = "asdf";
constexpr const char *x = p1 + 2; // OK!
constexpr char y = p1[2]; // OK!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

地址常量表达式 的相关文章

随机推荐

  • Newtonsoft.Json.JsonReaderException

    我的 Newtonsoft Json 有问题 我正在尝试从 URL 解析 JSON 但收到错误 这是 JSON ID 0 Nome we Data 2013 09 16 Orario 00 00 16 Prestazione dfg Sta
  • Kotlin 中使用 Retrofit @PartMap 的多部分请求错误 (Android)

    如果我在 Java 中使用这段代码 那么它工作得很好 当我在 kotlin 中转换该代码时 出现错误 Logcat 08 20 23 46 51 003 3782 3782 com qkangaroo app W System err ja
  • 我何时以及为什么要使用 ARC 将局部变量声明为 __weak?

    Mike Ash 撰写了 ARC 简介 http www mikeash com pyblog friday qa 2011 09 30 automatic reference counting html他在那里介绍了这样的内容 weak
  • WPF控件默认大小

    为 wpf 应用程序定义自定义资源主题时 我可以设置宽度 高度等 如何找到这些属性的默认值 即框架中提供的控件中使用的值 WPF 控件通常不包含任何类型的默认大小 WPF 的主要功能点之一是 除非您指定大小 否则所有内容都会动态调整大小 如
  • TransitionEnd 事件未触发?

    我有多个元素 每个元素都以 某种程度上 持续时间进行动画处理 我使用 CSS3 过渡 jQuery 库和transitionend辅助函数来自大卫 沃尔什 https davidwalsh name css animation callba
  • 如何通过函数设置指针引用

    在 C 中 我尝试通过将指针发送到函数来设置指针的值 但该值不会在函数外部更改 这是我的代码 include
  • Java - NoSuchMethodError 未被异常捕获[重复]

    这个问题在这里已经有答案了 我的印象是 Exception 非常适合捕获所有可能的异常 因为它们中的每一个都以 Exception 作为基类 然后 在开发 Android 应用程序时 我使用了以下方法 该方法在某些自定义 ROM 中已被删除
  • Django:重置密码不发送电子邮件

    我正在使用 Django 密码重置 我的代码中有这个代码设置 py EMAIL USE TLS True EMAIL HOST smtp gmail com EMAIL PORT 587 EMAIL HOST USER email prot
  • 如何在Android中设置对话框的图标

    我想在Android中自定义一个对话框 我知道如何设置对话框的标题 dialog setTitle O message 现在我想在标题前面设置图标 我怎样才能实现这个目标 Dialog dialog dialog new Dialog th
  • 创建全球唯一的 Android 标识符

    说到Android唯一ID 相信大家都见过this https stackoverflow com questions 2785485 is there a unique android device id 但是我也试图提出一个解决方案来唯
  • Storybook 和 AntDesign 组件 - 如何使用 CRA 和 Typescript 进行设置?

    我想使用 Typescript 在我的 CRA 项目中使用基于 AntDesign 组件构建的组件来设置 Storybook CRA v3 故事书 v5 25 AntDesign v3 23 2 我成功设置了 CRA AntDesign 设
  • 将按钮固定到容器的底角

    我正在使用 Flexbox 使表单垂直和水平居中 在此表单中 我想将一个按钮固定到 Flexbox 容器的右下角 我不知道如何将按钮固定在右下角 html body height 100 container height 100 displ
  • 具有多个 orderBy 的 Android firebase 查询

    我想检索我的 firebase 数据库中所有类型为 福音 的数据 这是我的数据库 DatabaseReference infoRef FirebaseDatabase getInstance geReference child info i
  • std::setw 如何处理字符串输出?

    我正在尝试使用设置宽度setw但是 对于将字符串输出到输出文件 我无法使其工作 我有下面的例子 setw example include
  • pine、node.js (express) 和 Access-Control-Allow-Origin

    我正在本地电脑上开发一个应用程序 前端应该使用 spinjs 构建 后端 api 使用 node js 构建 Spine 运行在端口 9294 上 node js 运行在端口 3000 上 在 Spine 中 我在模型中添加了以下内容 ur
  • 从 Mailgun 表单 Post PHP 中检索附件

    如何检索并保存通过 Mailgun 的 POST 表单发送给我的附件 下面是一些参数 attachment 1 filename gt crabby gif type gt image gif name gt attachment 1 te
  • 获取对 JOptionPane 静态方法创建的对象的引用

    我想知道是否可以获取对由 JOptionPane 的静态方法之一 例如 showMessageDialog 创建的 JDialog 对象的引用 我打算修改对话框在屏幕上出现的位置 更具体地说 我希望对话框默认显示在主应用程序窗口的左上角 而
  • viewroot 构建后如何应用 JSF2 PhaseListener?

    在我的 JSF2 应用程序中 我有一个阶段侦听器 需要在 RENDER RESPONSE 之前但在 JSF 构建 viewroot 之后执行 首先 我所做的就是在 faces config 中注册我的 PhaseListener 然后监听器
  • 加载外部 XSLT 时发生异常

    我有大量来自第三方的 XSLT 我需要用它来转换一些数据 如果我使用 xsltproc 它工作正常并按预期输出数据 我有以下 C 代码来尝试在进程中使用它 sXML 是 XML 的集合 oJob ContentTemplate 是 XSLT
  • 地址常量表达式

    我在阅读 C 编程语言第四版 一书时正在深入研究地址常量表达式 它有一个简短的段落描述了地址常量表达式 静态分配对象的地址 例如全局对象 变量 是常数 然而 它的值是由链接器分配的 而不是编译器 因此编译器无法知道 这样的地址常量 这限制了