c - C中的数组 "implemented"如何?

标签 c arrays pointers gcc

数组显然不是指针。可以肯定的是,两个 lvalues 似乎都包含(一维)虚拟内存中某个位置的(一维)坐标。但是考虑这个例子。

#include <stdlib.h>
#include <stdio.h>
int main(){
  char buffer0[4096];
  char* buffer1 = malloc(4096);
  printf("lvalue %16p  sizeof %lu\n", (void *) buffer0, sizeof(buffer0));
  printf("lvalue %16p  sizeof %lu\n", (void *) buffer1, sizeof(buffer1));
// Example output:  lvalue   0x7ffcb70e8620  sizeof 4096
// Example output:  lvalue         0x7a4420  sizeof 8
}
想到的

实际差异是:

  1. 数组知道它们有多大(以字节为单位)(并且,通过扩展,它们知道它们有多少个元素);指针不知道(但 malloc() 必须 知道指针有多大,才能知道仅给定指针的 free() 有多少...!)
  2. 数组是“垃圾收集器”(不需要 free() 它们);必须手动释放指针(如果它们拥有大量内存,即通过 malloc())
  3. 数组“活”在堆栈中(高虚拟内存地址,至少在我的平台上);指针“活”在堆中(低虚拟内存地址)
  4. 数组在传递给函数时衰减为指针
  5. 数组不能调整大小;指针可以

总的来说,数组似乎比指针更聪明(但通用性较低)(它们知道它们有多大,它们有多少元素,并且它们具有自动内存管理)。


问题

  1. 数组如何“知道”它们有多大?这是如何实现的?
  2. 一般来说,数组在C语言中是如何实现的? (编译器会这样做,还是内核会这样做?

最佳答案

How do arrays "know" how big they are? How is this implemented?

数组不知道它们有多大——没有与数组关联的元数据来指示大小(或类型,或其他任何内容)。 在翻译过程中,编译器知道数组有多大,并且在那个时候处理任何依赖于该知识的知识(指针算术、sizeof 操作等)。一旦生成了机器代码,数组就只是一些愚蠢的内存块——在运行时无法通过查看数组对象本身来确定数组有多大(可变修改类型除外,如变量-length 数组,sizeof 操作是在翻译期间计算的,而不是运行时)。

In general, how are arrays implemented in the C language? (Does the compiler do this, or does the kernel?

数组只不过是同一类型对象的连续序列。对于声明

T arr[N]; // for any type T

你得到

     +---+
arr: |   | arr[0]
     +---+
     |   | arr[1]
     +---+
     |   | arr[2]
     +---+
      ...
     +---+ 
     |   | arr[N-1]
     +---+

没有独立于数组元素本身的 arr 对象,也没有为大小、起始地址、类型或其他任何内容预留任何元数据。

下标操作arr[i]定义*(arr + i) - 给定数组的起始地址,偏移量i 个元素(不是字节!)并解引用结果。

你说数组不是指针是正确的 - 但是,除非它是 sizeof 或一元 & 运算符的操作数,或者是用于初始化 a 的字符串文字声明中的字符数组,数组类型的表达式将被转换(“衰减”)为指针类型的表达式,表达式的值将是数组第一个元素的地址(同样,这一切都是在翻译期间完成的,而不是在运行时)。

因此,当您编写类似x = arr[i]; 的代码时,编译器会将表达式arr 转换为指针值,因此下标操作有效。

相比之下,当您编写 ap = &arr; 时,编译器不会arr 转换为指针类型。结果仍然与第一个元素的地址相同,但是类型不同——不是T *,类型是T (*)[ N],或“指向 T 的 N 元素数组的指针”。

关于c - C中的数组 "implemented"如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50450578/

相关文章:

c - (C) 二维数组函数

c - 了解 C 中的 addLast 方法

将 *.raw 转换为 *.tiff

Java Array Index out of Bounds 异常 with/for 循环

阐明 GNU C 库如何定义不可重入函数

javascript - 在 React Native 中更新嵌套状态对象?

javascript - 编写一个通用实用程序,可以从 javascript 中的任何数组中删除重复项

c++ - 我如何访问一个指针子类方法,那些方法是子类独有的?

c++ - 如果 Malloc 无法分配 X 字节,我是使用 Realloc 还是再次使用 Malloc? C++

C 返回结构体指针