C++将固定大小的数组的大小存储在哪里?

4
这个问题是关于声明int数组的后续问题。
考虑下面的程序:
#include <iostream>
#include <string>

int main()
{
  int x[10];
  std::cout << sizeof(x) << std::endl;
  int * y = new int [10];
  std::cout << sizeof(y) << std::endl;
  //delete [] y;
}

sizeof(x)输出40(总大小),sizeof(y)输出8(指针大小)。

对我来说,这很有趣。在我的看法中,int x[10]y没有任何区别,除了它在栈中的位置不同外。那么c++实际上是从哪里存储x的大小呢?它是从栈中获取的吗?或者固定大小的数组在内部被视为具有大小的结构体?


2
它根本不存储它。如果需要,请使用std::array<int,10> - user0042
4
它不会(存储大小),编译器了解 x 的完整类型,其中包括数组的大小。y 只是一个指针(不是数组),所以编译器只知道它的这些信息。另外需要注意的是:sizeof 在编译时而不是运行时被评估。 - Richard Critten
2
@user0042,即使是std::array也不存储大小。至少我希望实现不会这样做。 - chris
7
对于像问题中的 x[10] 这样的固定大小数组,编译器会在编译代码时“存储”其大小,例如 sizeof(x) 最终会成为编译代码中的常量40。正如 Richard Critten 所指出的那样,sizeof() 在编译时被求值。 - rcgldr
2
这是类型的一部分。int[10]int[8]是不同的类型。编译器知道这些信息,因此可以获取它们的大小。 - NathanOliver
@rcgldr,编译时操作符看起来不错,你可以把它作为一个答案吗? - James Maa
3个回答

4

数组的大小不需要被存储,编译器自己知道它有多大,因为它是类型的一部分。

当你像在例子中使用y一样动态分配数组时,数组的大小确实需要被存储在某个地方,以便delete[]可以做正确的事情。但这是一个程序无法访问的实现细节。


3
你有两种不同类型:
int x[10];

这声明了一个类型为int[10]的数组。正如您所看到的,数组的大小是类型的一部分。
int * y;

这是一个指向int的指针。它的大小与您系统上指针的大小相同。您的系统似乎有64位指针(现在很普遍)。


以下是C++17中的一个小技巧:

template<class T>
std::enable_if_t<std::is_pointer_v<T>> foo(T ptr)
{
    std::cout << "Called foo for a pointer type" << std::endl;
}

template<class T, int N>
void foo(T (&arr)[N])
{
    std::cout << "Called foo for an array type of size " << N << std::endl;
}

我们定义了两个名为foo的函数。第一个函数使用类型特征仅对指针类型启用,而第二个函数是针对数组类型(通过引用)的。
我们可以从主函数中调用它们:
int x[10];
int * y = nullptr;
foo(x);
foo(y);

并获得如下输出:

调用大小为10的数组类型的foo函数
调用指针类型的foo函数

可运行代码


编辑:Mark Ransom提到了分配给的数组大小,我也想补充一点。虽然这确实是一个实现细节,但通常内存分配器(如mallocnew)在底层会将此值写入它分配的内存块的开头。 这样,在调用delete时,您无需知道要删除多少字节; 释放器(freedelete)可以检查内存块的开头以获取其大小。因此,分配1个字节的内存可能实际上分配了更多的字节。(再次强调,这只是其中一种实现方式)


我喜欢这个答案,因为它提到了一些我之前不知道存在的东西。 - James Maa

2
数组的大小在编译后的C++代码(汇编代码)中可以看到。这相当于sizeof()在编译时进行求值。
因此,它不会存储数组的大小,编译器知道数组的大小。
当您动态分配内存时,编译器再次知道数组的大小并记住它(它在何处以及如何实现是有定义的)。因此,当您调用delete[]时,您不需要指定数组的大小,编译器已知道。

不是说这个回答不好,但它怎么不完全等同于@MarkRansom的回答呢? - Jonathan H
@Sheljohn 确实。我在 Mark 发布他的回答之前就开始写我的回答了(因为我在进行双重检查)... - gsamaras

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接