繁体   English   中英

[]运算符如何工作?

[英]How does the [] operator work?

我正在使用C,但是我认为这是一个更底层的问题,与语言无关。

程序如何使用array [0]或array [6]正确地获取正确的数据,而不管它保存的数据类型是什么? 它在内部存储长度还是要寻找某种分隔符?

编译器知道基础数据类型的sizeof ,并将正确的字节偏移量添加到指针。

a[10]等效于*(a + 10) ,后者等效于*(10 + a) ,后者又等效于10[a] ,没有开玩笑。

编译器在编译时计算出大小,并在目标代码中对大小进行硬编码。

除了直接回答外,我还想提供一些其他信息。

在Dennis Ritchie的C历史主页上有一篇有趣的文章,其中有很多关于数组,数组索引等方面的文章。

这可能不会直接回答您的问题,但可能会使您对C数组有进一步的了解。

都不:-)

对于数组,编译器知道:(a)数组开始的地址,以及(b)数组包含什么类型的元素(int,float,double等),以及每个元素的长度。

利用这两条信息,找到array[6]是一个简单的算法问题:从基地址开始,再加上元素大小的6倍。

编译器将替换在编译时固定的数据类型的长度。

int getInt(void * memory, offset)
{
     return *((int *)(sizeof(int)*offset + memory))
}

void * chunkOfMemory = malloc(0x1000);
int * intarray = (int *) chunkOfMemory;
printf("%d is equal to %d", getInt(chunkOfMemory, 9), intarray[9]);

编译器在编译时知道数组每个元素的大小。 例如:

int64_t array[5];
...
int64_t a = array[3];

这将被转换为伪汇编代码:

addr <- array
addr <- addr + 3 * sizeof(int64_t)
//                 ^^^^^^^^^^^^^^^ which the compiler knows is 8
//             ^^^^^^^^^^^^^^^^^^^ which the compiler can replace with 24.
a <- *addr 

数组的长度无关紧要。

这是编译器的魔力

编译器知道数组元素的大小,并使用它来计算正确的地址。

是的,您是对的,甚至更低级的问题,甚至汇编器都有[]运算符。 这个答案说的很好,但我的解释是:

arr[x]*((void *)(&arr) + x * sizeof(arr[0]))

看起来有点复杂,但是生成的代码很简单。 这是因为编译器知道sizeof(arr[0])并且在编译代码中进行了硬编码,而且(void *)(&arr)只是一种语言标准,可以保护程序员免受愚蠢的错误,并且在编译代码中没有类型转换。

正如我提到的低级语言一样,还有一件事需要提高。 使用它们,您可以重载运算符,并使它做您想做的任何事情。

不,不是。 它只是在地址array + X*sizeof(TypeOfArrayEl)处获取/设置元素,因此您可以轻松地越界,并且那时没有人会给您错误。 这就是为什么array[6]6[array]相同的原因

假设数组的类型为int:

int array[12];

[]运算符将括号内的任何值(乘以数组类型的字节大小)乘以括号外的值。 数组由实现存储为指向其第一项的指针。 因此,上面的数组声明分配了12 * sizeof(int)个字节,并使array指向第一个。 这会导致像3[array]这样的古怪的东西给您3[array]的第三个元素。

无论如何,问题的答案是编译器在编译时查看数组的类型,然后将[]中的值乘以数组持有的类型的大小。

据我所知,如果索引超出范围,C不会给您一个编译时错误。 即使您超出范围,指针也只会为您提供下一个相邻的存储位置。 C唯一需要照顾的是增加多少字节的指针。 如果它是一个整数数组,则指针将针对索引中的每个增量前进2个字节,对于char类型的指针将递增1个字节。

您始终可以访问超出范围但是垃圾数据的位置,而作为程序员,您必须确保访问的数据正确。

我猜这就是自由的代价:)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM