constexpr 指针如何存在并且 constevel 函数在编译时返回指针?

How can constexpr pointers exist and constevel function return a pointer at compile time?

提问人:Akshay J R 提问时间:11/1/2023 最后编辑:Akshay J R 更新时间:11/1/2023 访问量:129

问:

我正在浏览 constexpr 和 consteval 的主题,并发现了以下内容,

  1. 我们可以有 CONSTEXPR 类型的指针
  2. CONSTEVAL 函数可以返回 CONSTEXPR 变量的指针

我在这里的问题是,上述 2 怎么可能?

以上 2 个问题是因为,据我所知,所有变量都是在运行时在内存中创建的,指针是该内存的地址。

那么,CONSTEXPR 类型的指针是如何存在的(因为 CONSTEXPR 变量必须在编译时初始化)?以及 CONSTEVAL 函数如何在编译时返回 CONSTEXPR 变量的指针?

   #include <iostream> 

   constexpr int a{1};

   consteval const int* aptrfunc()  //How can this function return a pointer at compile time
   {
       return &a;
   }

   int main()
   {
        constexpr const int* aptr{&a};   //How can this exist at compiletime?
        std::cout<<aptr<<'\n';           //Prints address of a
        std::cout<<aptrfunc()<<'\n';     //Prints address of a
        return 0;
    }
C++ 指针 constexpr consteval

评论

2赞 Passer By 11/1/2023
我很确定编译器以符号方式处理编译时指针。如果选中,您将看到在编译时无法获取指针的数值。
0赞 HolyBlackCat 11/1/2023
constexpr-ness 不是类型的一部分,它是变量(或函数或其他东西)的单独属性。
0赞 user12002570 11/1/2023
基本上,全局对象(在任何函数之外定义的对象)具有“固定地址”,因此指针可以指向它。constexpr
0赞 Cem Polat 11/1/2023
@PasserBy确切的指针地址不一定在编译时知道,但如果指针及其值可以在编译时确定,编译器至少可以区分 constexpr 是否可以用于涉及指针的表达式。这完全是关于值和地址的编译时与运行时的可确定性,以及编译器在编译时基于该可确定性计算表达式的能力。
0赞 Red.Wave 11/1/2023
变量的生存期是 C 教育的重要组成部分,在 C++ 中变得更加明显。如果你读过你的书,你一定知道存储类的含义。 对象具有存储类,这意味着它们具有静态持续时间。也就是说,它们的地址是在编译时确定的。在关键字之前,不得不在运行时浪费 cpu 周期来获取编译时可用的此类信息真的很烦人。如果你有过汇编程序的经验,你就会知道有一个部分或其他东西。constexprstaticcostexper.data

答:

0赞 user12002570 11/1/2023 #1

以上 2 个问题是因为,据我所知,所有变量都是在运行时在内存中创建的

是的,但并非所有人都有固定地址。

就标准而言,允许 constexpr 指针指向保持在固定地址的对象。在任何函数(全局对象)之外定义的对象都有一个固定的地址,因此它的地址可以用来初始化 constexpr 指针。

就像你的例子一样,是一个全局的,因此保持在固定地址,所以可以制作一个 constexpr 指针来指向它。aint

实现/编译器可能会以符号方式处理此类 (constexpr) 指针,但这是实现细节。

0赞 JaMiT 11/1/2023 #2

指针是该内存的地址

嗯,不完全是。cppreference.com 使用的措辞是“代表地址”。指针允许程序访问它所指向的内容比指针具有特定值或位模式更重要。你越来越想知道某个价值。

如果你抽象地思考,你可以用指针做很多事情,而不知道确切的地址。例如,您可以确定两个指针是否指向同一地址。您可能不知道确切的地址,只知道它们是相同的。在实践中,对值有效的地址在编译时是已知的,直到操作系统在运行时提供的偏移量,并且在整个执行过程中是固定的。这足以确定两个指针是否相等。同样,在需要常量表达式的地方,“最多一个偏移量”足以让编译器执行它需要执行的操作。constexpr

有趣的是,不需要常量表达式的一个地方是流式处理运营商的操作数。也就是说,在表达式中,不需要编译器能够准确确定将显示哪些字符。相反,可以在运行时确定输出字符。在这方面,在程序执行之前无法查看 的值。但是,在编译时,尽管无法显示确切的值,但已知表达式表示 的地址,这对于所有(合法的)编译时处理来说已经足够了。std::cout<<aptraptraptra

评论

0赞 Passer By 11/1/2023
“值在编译时已知,直到偏移量”,但事实并非如此。每个 TU 都是独立编译的,编译器无法知道 or 变量的位置。externinline
0赞 JaMiT 11/2/2023
@PasserBy 将“编译时”与“运行时”进行对比时,传统上将链接器作为编译器的一部分包含在内。链接器知道变量在程序中的最终位置。(这里还有比“编译时”更好的术语吗?
0赞 Passer By 11/2/2023
在实践中,链接器对 一无所知。编译器必须单独解析指针。例如,将触发,它与链接器无关。constexprconstexprstatic_assert(aptr != aptrfunc());
0赞 JaMiT 11/4/2023
@PasserBy 正如我在问题中所说,编译器有足够的信息来做它需要做的事情,人们不应该纠结于正在使用的确切值。我不认为深入研究细节会增加这个答案的价值。把它作为一个家庭作业练习,弄清楚如何取一个“代表地址的链接器符号”和另一个“代表地址的链接器符号”,并得出结论,它们在不参与链接器的情况下是相等的。aa