编译器如何知道数组C++长度
How C++ compiler knows the length of an array
例如,在main函数中,我可以写int arr[42]
,并且我可以使用范围为循环而不指示其长度for (auto i : arr)
。效果很好。编译器将知道它的长度。
如果我将此数组传递给另一个函数,例如 void foo(int arr[])
,我无法使用 range for 循环,因为编译器不知道它的长度。
毕竟,如果我有这个模板template<class T, size_t N> void arr_init(T (&foo)[N])
,我可以通过arr_init(x)
调用它。显然,编译器调用arr_init(int (&)[42])
.
我猜编译器通过它的声明int[42]
知道数组的长度。我说的对吗?当我使用循环范围并学习模板时,我遇到了这个问题。我以前在使用 C 时没有遇到过这样的问题。
类型T[N]
不同于T[M]
类型T
的数组类型,以及两个不同的大小N
和M
。因此,数组的长度内置于类型中。
OTOH,数组会自动衰减到函数调用参数列表中的指针。换句话说,这三个函数签名之间没有区别:
int func(int []);
int func(int[5]);
int func(int[10]);
int func(int*);
以上所有签名都只是在int*
.如果要保留数组类型,则需要创建一个将数组引用作为参数的函数。这正是您在示例中实现的 template<class T, size_t N> void arr_init(T (&foo)[N])
.在 arr_init
中,foo
的行为类似于数组,因为它是对数组类型的引用。
对于类型为 T[N]
的数组arr
,基于范围的for
分别使用表达式 arr
和 arr+N
作为起点和终点。
对于类类型,成员函数 begin
和 end
(如果存在)用于确定端点,否则将使用非成员重载、begin
和end
。
(begin
和end
,而不是std::begin
和std::end
,因为标准库中begin
和end
的通用用法是这样的:
using std::begin;
begin(...);
using std::end;
end(...);
这允许 ADL 查找用户定义的begin
并end
重载。
是的,你是对的。这是因为编译器知道在同一翻译单元中定义的对象的大小。
事实上,你不需要使用范围 for 循环来查看类似的行为;你可以使用普通sizeof
。
foo.c:
#include <stdio.h>
extern int a[];
int main()
{
printf("%dn", sizeof(a));
}
酒吧:
int a[50];
现在测试:
gcc foo.c bar.c
> foo.c: In function 'main':
> foo.c:7:23: error: invalid application of 'sizeof' to incomplete type 'int[]'
每当你通过引用传递数组时,你都可以推断出它的大小(记住数组不是指针)。因此,基于范围的 for 使用的函数 std::begin()
和 std::end()
对于数组来说可能是像这样重载的
namespace std
{
template<typename T, std::size_t N>
T* std::begin(T (&arr)[N])
{
return arr;
}
template<typename T, std::size_t N>
T* std::end(T (&arr)[N])
{
return arr + N;
}
}
数组仅在按值传递时才衰减到指针,例如
void f(int arr[256]){...}
这是句法糖
void f(int* arr){...}
PS:看起来基于范围的for
不使用std::begin
和std::end
,因为编译器在编译时知道数组的大小(如 @T.C 所述)。所以上面的代码仅用于演示目的;)
有关基于范围的for
的更多详细信息,请参阅标准的 6.5.4:
在每种情况下,基于范围的 for 语句等效于
{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
6.4.3/1 如果_RangeT是数组类型,则分别__rangebegin-expr 和 __range+ __bound,其中 __bound 是数组绑定。如果_RangeT是未知大小的数组或不完整类型的数组,则程序格式不正确;
- 从C字符串中获取奇怪的字符串长度
- 如何在数组中找到字符串的长度
- 获取字符串的长度并将其分配给数组
- 数组长度,为什么从命令行获取时不能使用它?
- 在一定长度后从数组中打印时缺少整数
- 为什么这个 c++ 代码打印出长度 5,当我打印出字符串时,程序会自动终止?
- 在C++中查找范围的长度
- 带有指定长度字符* 参数的 std::regex_search 在 VS2017 中不起作用?
- 如何创建长度由常量参数指定的数组
- 求最长递增子序列C++的长度
- 如何在 nlohmann 的 json 库中获取数组长度?
- 使用C++进行运行长度解压缩
- 如何计算数组中元素的位数?(不是数组的长度),并计算其数字的总和
- 如何将可变长度参数联接为字符串
- 我应该如何从 stdin C++ 中读取可变长度的格式字符串?
- 如何从txt文件中读取多个不同长度的数组?
- 按边长度递归搜索图中所有可行路径
- 在将 new 与指针一起使用时,创建数组的指定长度
- 通过字符串来计算长度需要更长的时间,而不是移动字符串几次?
- 为什么字符串比较的 == 运算符相对于任一字符串长度线性时间(似乎)?