我想知道是什么定义了内存对象的起始位置是低于还是高于对象末尾的地址。例如:
char buffer[10];
char* p = &buffer[0];
printf("%p\n",p); //0x7fff064a6276
p = &buffer[9];
printf("%p\n",p); //0x7fff064a627f
在此示例中,对象的开头位于比结束更低的地址。即使堆栈朝着较低的地址增长。
为什么布局会与堆栈增长的方向相反?
是什么定义了这个方向?语言? OS?编译器? CPU架构? ...
对象的结尾是否始终高于开头的地址?
答案 0 :(得分:2)
相关标准的一部分在§6.3.2.3指针(根据§6.3转换):
¶7...当指向对象的指针转换为指向字符类型的指针时,结果指向对象的最低寻址字节。结果的连续增量,直到对象的大小,产生指向对象剩余字节的指针。
另一个相关部分是§6.7.2.1结构和联合说明符:
¶15在结构对象中,非位字段成员和位域所在的单元具有按声明顺序增加的地址。指向适当转换的结构对象的指针指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。可能有未命名的 在结构对象中填充,但不在其开头。
加法(和减法)的定义部分相关(§6.5.6加法运算符):
¶8当一个具有整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向偏离原始元素的元素,使得结果与原始元素的下标不同 数组元素等于整数表达式。换句话说,如果表达式
P
指向数组对象的i
- 元素,则表达式(P)+N
(等效地,N+(P)
)和(P)-N
(其中N
的值为n
)分别指向数组对象的i+n
- 和i−n
- 元素,前提是它们存在。此外,如果表达式P
指向数组对象的最后一个元素,则表达式(P)+1
指向数组对象的最后一个元素之后,如果表达式Q
指向一个数组对象的最后一个元素,表达式(Q)-1
指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出;否则,行为未定义。如果结果指向一个超出数组对象的最后一个元素的结果,则它不应该用作被计算的一元*
运算符的操作数。
¶9是一个定义减法行为的类似段落。
然后是§6.5.2.1数组下标:
¶2后缀表达式后跟方括号
[]
中的表达式是下标 指定数组对象的元素。下标运算符[]
的定义 是E1[E2]
与(*((E1)+(E2)))
相同。由于转换规则 应用于二进制+
运算符,如果E1
是一个数组对象(等效地,指向 数组对象的初始元素)和E2
是一个整数,E1[E2]
表示E2
- thE1
的元素(从零开始计算)。
从这些中,您知道转换为char *
的对象的地址必须指向保存该对象的最低字节地址。实际上,这意味着对象的“对象指针”地址也指向最低地址。该规则决不会强制int
类型中的数据必须为little-endian或big-endian;两者都有效。
您还知道结构中的第一个元素位于结构中的地址低于后面的元素。
答案 1 :(得分:1)
大多数编译器会在堆栈中为一个块中的所有局部变量分配空间,最低地址处的数组的开始向上。
您需要转到更深的子程序才能看到地址“正在下降”。
例如,调用其他也有本地缓冲区的子程序。你会发现地址空间中的内存“较低”(因为堆栈变得更大)是父例程中的本地数组。