考虑以下代码:
int A[5] = {0,1,2,3,4};
int i=1;
int test = A[i];
Run Code Online (Sandbox Code Playgroud)
此代码生成的 MIPS 程序集将向左移动i 2 位以乘以 4,因为我们获取的是 int(4 字节)。我完全理解这一点。
现在如果我们设置
int i = -1; //or any negative number
Run Code Online (Sandbox Code Playgroud)
生产的组件实际上是相同的。但是在这里,我们将一个负数移动了 2 位,这实际上可以返回一个正数。所以,我的问题是, A[negative_number] 不会用这个负数来抵消地址,但它会产生一个有点随机的结果,对吧?
左移-12 位产生-4,这是添加到第 -1 个位置的正确字节偏移量。
如果i非常大以至于结果溢出,左移只会产生一个正数。但是,只有当您尝试访问超出 -2 29 th 索引(假设为 32 位int)时才会发生这种情况,这当然是首先要求的索引太大(小?)。
顺便说一句,只有当您从对象中间的指针开始并且负索引仍在访问有效内存时,访问负索引才有效。A[-1]会调用未定义的行为。一个更好的例子是:
int *p = &A[3];
int i = -1;
int test = p[i];
Run Code Online (Sandbox Code Playgroud)
这里p[-1]解析为(&A[3])[-1]which 等价于A[2]。这是一个有效的索引,所以p[-1]是合法的。
此外,虽然在汇编代码中很好,但应该注意的是,在 C中左移负数是 undefined。不要试图-1 << 2用你的 C 代码编写。编译器可以代表我们做,但我们不能自己写。
如果
100001向左移动一次会怎样?你会得到000010,这在我的书中是积极的。
只有当ints 为 6 位宽时才会出现这种情况。根据 C 标准,它们必须至少为 16 位宽,在现代计算机中通常为 32 位,有时为 64 位。
假设我们在 16 位系统上。100001实际上是这两个数字之一:
0000000000100001. 这是 33,一个正数。1111111111100001. 这是-31,一个负数。将其左移将保留除前导1位之一之外的所有位并保持为负。