为什么这个'C'代码的输出是这样的?

neo*_*neo 1 c memory

我有以下C代码:

#include<stdio.h>
#include<stdlib.h>
int main() {

int a[4] = {1,2,3,4};

int b[4] = {1,2,3,4};

int n = &b[3] - &a[2];

printf("%d\n", n);

return 0;
}
Run Code Online (Sandbox Code Playgroud)

为什么值为n-3?我对此没有一个纯粹的解释.变量地址之间的区别如何-3?为什么呢-3

Eri*_*hil 14

虽然当你减去指向不同数组中元素的指针时,C标准没有定义行为,但似乎发生的事情是你的编译器就b在之前(比地址低)放入内存a.因此,内存布局看起来像:

+------+------+------+------+------+------+------+------+
| b[0] | b[1] | b[2] | b[3] | a[0] | a[1] | a[2] | a[3] |
+------+------+------+------+------+------+------+------+
Run Code Online (Sandbox Code Playgroud)

鉴于这种内存布局,&a[2] - &b[3]是+3因为a[2]内存中的三个元素比b[3].然后&b[3] - &a[2]是-3因为b[3]内存中的三个元素比a[2].(注意,这样的不符合C标准的简单指针算法可能会中断,因为编译器可能会执行各种优化,或者因为某些体系结构上的地址算法很复杂.C标准不仅不定义减法的结果;它一旦执行了未定义的减法,就不会定义程序的行为.)

许多C实现将对象放在堆栈上(如果它们具有自动存储持续时间,而不是静态,分配或线程),并且堆栈通常从高内存地址开始并向低地址增长.所以,如果编译器只是按照你声明它们的顺序为对象分配空间(这通常不是预期的;有很多理由做更好的事情),那么它会有效地a先放入堆栈,然后减少堆栈指针,然后放在b堆栈上,所以b最终的地址低于a.

顺便说一下,两个指针相减的结果有大小ptrdiff_t,这不一定int,所以它应该被印刷printf("%td\n", n);,而不是%d,并n应与被声明ptrdiff_t n;,而不是int n;.的ptrdiff_t类型是在限定的<stddef.h>报头中.