A[-1] 实际上 returns 是 A[0] 在内存中的前一个位置吗?

Does A[-1] actually returns the previous position in memory from A[0]?

考虑以下代码:

int A[5] = {0,1,2,3,4};
int i=1;
int test = A[i];

此代码生成的 MIPS 程序集将向左移动 i 2 位以乘以 4,因为我们获取了一个 int(4 字节)。我完全理解这一点。

现在如果我们设置

int i = -1; //or any negative number

生成的组件实际上是一样的。但是在这里,我们将一个负数移动 2 位,这实际上可以 return 一个正数。所以,我的问题是,A[negative_number] 不会将地址偏移这个负数,但它会产生有点随机的结果,对吗?

左移 -1 2 位产生 -4,这是为获得第 -1 位置而添加的正确字节偏移量。

如果 i 非常大以至于结果溢出,左移只会产生正数。但这只有在您尝试访问超出 -229th 索引(假设 32 位 ints)时才会发生,这当然太大(小? ) 首先要求的索引。

顺便说一句,仅当您从对象中途的指针开始并且负索引仍在访问有效内存时,访问负索引才有效。 A[-1] 会调用未定义的行为。一个更好的例子是:

int *p = &A[3];
int i = -1;
int test = p[i];

此处 p[-1] 解析为 (&A[3])[-1],相当于 A[2]。这是一个有效的索引,所以 p[-1] 是合法的。

此外,虽然在汇编代码中它很好,但应该注意left shifting negative numbers in C is undefined。不要试图在您的 C 代码中编写 -1 << 2。编译器可以代我们做,但我们不能自己写。

What if you shift 100001 one time to the left? You will get 000010, which is positive in my books.

只有 int 是 6 位宽时才会出现这种情况。根据 C 标准,它们必须至少有 16 位宽,而在现代计算机中通常是 32 位,有时是 64 位。

假设我们使用的是 16 位系统。 100001 实际上是这两个数字之一:

  • 0000000000100001。这是33,一个正数。
  • 1111111111100001。这是 -31,一个负数。将其左移将保留除前导 1 位以外的所有位并保持负值。
如果 C 标准使用的计算模型中存在这样的元素,

A[-1] 确实会在 A[0] 之前指定内存中的元素。如果 A 是数组则不会,但如果 A 是指针则可能:

int X[] = { 10, 11, 12, 13 };
int *A = &X[2];
printf("%d\n", A[0]);  // Prints “12”.
printf("%d\n", A[-1]); // Prints “11”.

如果 A[-1] 是计算模型。

左移一个负数只有在溢出时才会产生一个正数。

(C 标准根据简单的抽象计算机指定行为,其中所有对象都存储在内存中,并且每次使用对象都从其内存加载或存储到其内存。实际上,编译器优化并可能将对象保存在寄存器而不是内存,以及其他优化。任何具有定义行为的程序的最终结果应该与抽象模型中的程序具有相同的行为,但编译器可能会以与 C 标准描述它的方式截然不同的方式实现它。)