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

时间:2018-04-25 15:15:51

标签: 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;
}

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

3 个答案:

答案 0 :(得分:14)

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

a

鉴于此内存布局,+------+------+------+------+------+------+------+------+ | b[0] | b[1] | b[2] | b[3] | a[0] | a[1] | a[2] | a[3] | +------+------+------+------+------+------+------+------+ 为+3,因为&a[2] - &b[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>标题中定义。

答案 1 :(得分:4)

代码的行为是 undefined

指针算法,包括两个指针的减法,对指向同一数组中元素的指针有效。 (为此,您可以设置指向数组末尾的指针,对象计为包含一个元素的数组。)

答案 2 :(得分:-3)

使用C调用约定(在x86上),局部变量被推送到本地堆栈,因此在内存中相邻。

在这种情况下,两个数组在内存中相对相邻。 (确切的值可以通过字节/字/ qword对齐等方式实现)

最终结果是,您可以获得一致的值,这可以根据您的构建环境/选项进行预测。