C++ 所有变量是否根据在程序中声明的顺序连续存储?

C++ 所有变量是否根据在程序中声明的顺序连续存储?,c++,callstack,C++,Callstack,我正在学习数组,以及当你试图写一个越界的数组时,它是如何对你的程序有害的。当我发现这一点时,我试着读一些越界的东西 我玩了一个char数组和一个char变量 //这发生在int main()中 字符元音[]{'a','e','i','o','u'}; char x='x'; 标准::cout 这让我想知道是否所有变量都是按声明顺序连续存储的 不,C++在这种情况下唯一保证的是,当使用变量名读取值时,您将得到它。它们存储在内存中的顺序,甚至它们存储在内存中的顺序都无法保证,这样做对您来说最糟糕的事

我正在学习数组,以及当你试图写一个越界的数组时,它是如何对你的程序有害的。当我发现这一点时,我试着读一些越界的东西

我玩了一个char数组和一个char变量

//这发生在int main()中
字符元音[]{'a','e','i','o','u'};
char x='x';
标准::cout
这让我想知道是否所有变量都是按声明顺序连续存储的

不,C++在这种情况下唯一保证的是,当使用变量名读取值时,您将得到它。它们存储在内存中的顺序,甚至它们存储在内存中的顺序都无法保证,这样做对您来说最糟糕的事情——访问越界实际上是使您的整个程序无效,并且从语言的角度来看,您不能再从您的程序中期待任何东西。

来自标准():

将不等指针与对象进行比较的结果定义为符合以下规则的偏序:

  • 如果两个指针指向同一数组的不同元素或其子对象,则需要指向下标较高的元素的指针进行较大的比较

  • 如果两个指针递归地指向同一对象的不同非静态数据成员或此类成员的子对象,则需要指向后一个声明成员的指针进行更大的比较,前提是两个成员具有相同的访问控制([class.access]),两个成员都不是大小为零的子对象,他们的班级不是工会

  • 否则,两个指针都不需要比另一个指针大。

由于前两个条款不适用于将
x
的地址与
元音的地址或其元素进行比较,因此它们的地址没有意义上的可比性

但在这种情况下,特别是指针
元音+5
元音[5]
尝试取消引用的地址)具有特殊含义。任何指向具有
n
元素的数组的索引
n
处的假设元素的指针都称为“超过结束指针的指针”。它表示数组结束后的第一个字节。允许计算此地址,但不能取消引用。该标准有一个注释,明确指出您根本不能使用
元音[5]

[…]超过对象结尾([expr.add])的指针不被视为指向可能位于该地址的对象类型的不相关对象。[……]

因此,即使
x
正好位于
元音+5
,您仍然不允许通过
元音[5]
访问它

这让我怀疑是否所有变量都连续存储在 声明的顺序

不,或者至少语言没有指定它(见弗朗索瓦·安德烈)。内存中变量(特别是堆栈上的非成员变量)的布局由编译器决定。由于编译器必须处理诸如对齐之类的体系结构需求,因此它可以重新安排变量,并在它们之间留下间隙。这对于优化非常重要

下面是一个示例(x86-64),其中编译器(clang-9)不按声明顺序布局变量

#包括
int main(){
字符a[]{'a','b'};
int x;

STD::CUT C DUPE:试图找到C++版本,不是全部。静态变量可以按顺序创建。例如,UB:你根本没有保证…任何事情都可能发生。我相信这是一个实现细节,而不是标准所规定的。使用(或滥用)实现细节不被C++支持,并且直接地处于未定义行为的范围内。这就是坏事发生的地方。这可能发生,但它不能保证。-你的程序包含未定义的行为,因此没有意义。任何事情都可能发生(并且是一个有效的解释)。
&a[0] = 0x7ffd5becf02a
&a[1] = 0x7ffd5becf02b
&x = 0x7ffd5becf024