所以,我知道编写C ++代码的人可以这样做:
double *doublePtr; // Declares a pointer.
double doubleVal = 8.234; // Declares and initializes a double.
doublePtr = &doubleVal; // Makes pointer point to doubleVal.
此外,编写C ++代码的人可以这样做:
double doubleVal = 8.234; // Declares and initializes a double.
double &doubleRef = doubleVal; // Declares/Initializes a reference
// To the address of doubleVal (???).
// But why isn't doubleVal instead
// &doubleVal if it's an address that
// &doubleRef is being initialized with.
那么,为什么不适合(由于编译器错误)这样做:
double dVala = 1.234, dValb = 3.456;
&dVala = &dValb;
更具体地说,我试图提出这样一个问题,“我对此感到困惑的是什么,通过一个简单的解释,将使这一点的具体细节更加明确”。是否引用了C ++常量的内置数据类型,以便它们只能用值初始化,但在初始化后不能随时更改?
当然,我们可以将变量地址的值输出到某种数据类型,如下所示:
double dVala = 23.456;
cout << &dVala;
我希望我的问题很明确。感谢。
答案 0 :(得分:7)
符号&
具有多种含义,具体取决于上下文:你不能只从一个地方拿它,把它放在另一个地方,并期望完全相同的事情发生。
除此之外:
是否引用C ++常量的内置数据类型,以便它们只能用值初始化,但在初始化后不能随时更改?
是。 所有引用本身都是不可变的,并且在初始化后无法重新定位。
正如我们上面所探讨的,写&someReference
实际上并没有“访问”引用本身;实际上,没有这样做的语法。
但是为什么不是doubleVal而不是doubleVal,如果它是&amp; doubleRef正在初始化的地址。
因为那时引用在很大程度上与指针无法区分,因此毫无意义(lol)。
请勿将double& doubleRef
视为&doubleRef
。不是。这是一个名为double&
的{{1}}。
引用“为你做解除引用”。它们直接绑定到对象而无需您自己获取地址。
这是该语言的礼物。
答案 1 :(得分:0)
我认为你会发现学习一些基本装配非常有启发性。这样,您就可以准确地看到您的C ++代码是如何用CPU的本地语言表达的。为了帮助您了解代码发生了什么,让我们将其分解为汇编。这是我从MSVC2013获得的所有优化关闭。每个块代表原始代码的一行:
double doubleVal = 8.234;
movsd xmm0,mmword ptr [test!_real (00000001`3f2948b8)]
movsd mmword ptr [rsp],xmm0
doublePtr = &doubleVal;
lea rax,[rsp]
mov qword ptr [rsp+8],rax
double &doubleRef = doubleVal;
lea rax,[rsp]
mov qword ptr [rsp+10h],rax
这里没有显示的是编译器以这样的方式设置代码,即在内存中有三个变量的空间。第一个是变量doublVal
,它位于存储在CPU寄存器rsp
中的存储器地址中。同样,doublePtr
和doubleRef
存储在rsp+8
和rsp+10h
(这些是十六进制值,顺便说一句)。这个间距反映了变量长度为8个字节的事实。
现在,前两个指令(movsd
)将一个常量值(8.234)移动到浮点寄存器中,然后将其移动到rsp
中存储的地址({{1}的位置) })。现在doubleVal
被初始化为您指定的常量。
下一个块采用doubleVal
的地址(存储在doubleVal
中)并将其复制到CPU寄存器rsp
,然后将rax
中的值复制到该地址rax
(rsp+8
的位置)。现在doublePtr
已初始化为doublePtr
。
第三个块与第二个块相同,但doubleVal
的地址被复制到变量doubleVal
(其地址存储在doubleRef
)中除外。这表明编译器使用指针实现了您的引用变量,这是相当典型的。