为什么数组的大小通过C ++编译器已知的引用传递给函数?

时间:2021-12-09 21:36:55

I know that when I want to pass an array to a function, it will decay into pointer, so its size won't be known and these two declarations are equivalent:

我知道当我想将一个数组传递给一个函数时,它会衰减成指针,所以它的大小不会被知道,这两个声明是等价的:

void funtion(int *tab, int size);

and

void funtion(int tab[], int size);

And I understand why. However, I checked that when I pass an array as a reference:

我理解为什么。但是,当我传递一个数组作为参考时,我检查了一下:

void funtion(int (&tab)[4]);

the compiler will know the size of the array and won't let me pass an array of different size as an argument of this function.

编译器将知道数组的大小,并且不允许我传递不同大小的数组作为此函数的参数。

Why is that? I know that when I pass an array by address, the size isn't taken into account while computing the position of the ith element in the array, so it is discarded even if I explicitly include it in the function declaration:

这是为什么?我知道当我按地址传递数组时,在计算数组中第i个元素的位置时不会考虑大小,所以即使我在函数声明中明确地包含它,它也会被丢弃:

void funtion(int tab[4], int size);

But what is different when I pass an array by reference? Why is its size known to the compiler?

但是当我通过引用传递数组时有什么不同?为什么编译器知道它的大小?

Note: I'm interested in arrays whose size is known at compile time, so I didn't use any templates.

注意:我对编译时已知大小的数组感兴趣,所以我没有使用任何模板。

I found a similar question on Stack Overflow, however it doesn't answer my question - it doesn't explain why the compiler knows the size of the array, there is just some information on how to pass arrays to functions.

我在Stack Overflow上发现了类似的问题,但它没有回答我的问题 - 它没有解释为什么编译器知道数组的大小,只有一些关于如何将数组传递给函数的信息。

3 个解决方案

#1


6  

Because it can, and because checking adds extra safety. The compiler knows the size of the array because you tell it so, right there in the function declaration. And since that information is available, why wouldn't it use it to signal errors in your source code?

因为它可以,并且因为检查增加了额外的安全性。编译器知道数组的大小,因为你告诉它,就在函数声明中。既然该信息可用,为什么不用它来表示源代码中的错误?

The real question is why your last example wouldn't do the same check. This is, unfortunately, another piece of C legacy - you are never passing an array, it always decays into a pointer. The size of the array then becomes irrelevant.

真正的问题是为什么你的最后一个例子不会做同样的检查。不幸的是,这是C遗留的另一部分 - 你永远不会传递一个数组,它总是衰变成一个指针。然后数组的大小变得无关紧要。

Could a check be added? Possibly, but it would be of limited use (since we are all using std::array now - right!?), and because it would undoubtedly break some code. This, for example:

可以添加支票吗?可能,但它的用途有限(因为我们现在都使用std :: array - 对!?),因为它无疑会打破一些代码。这个,例如:

void func (char Values [4]);
func ("x");

This is currently legal, but wouldn't be with an additional check on array size.

这是合法的,但不会额外检查数组大小。

#2


0  

Because there is no odd implicit type change committed by the compiler in the case. Normally when you write:

因为在这种情况下编译器没有提交奇怪的隐式类型更改。通常当你写:

void func(int[4]);

or

void func(void());

The compiler decides to "help" you and translates those into:

编译器决定“帮助”您并将其转换为:

void func(int *);

or

void func(void(*)());

Funny thing though - it wouldn't aid you in such a way when you try returning one of those. Try writing:

有趣的是 - 当你尝试归还其中一个时,它不会以这种方式帮助你。试着写:

int func()[4], func1()();

Ooops - surprise - compiler error.

哎呀 - 惊喜 - 编译错误。

Otherwise arrays are arrays and have constant size which can be acquired by using the sizeof operator.

否则,数组是数组并且具有恒定大小,可以使用sizeof运算符获取。

This however is often forgotten because of the compiler behavior noted above and also because of the implicit pointer conversion applied to objects of array type when such isn't expected. And this is very often. Though here are the few exceptions when no implicit array object conversion is applied:

然而,这经常被遗忘,因为上面提到的编译器行为,并且还因为在不期望这种情况时应用于数组类型的对象的隐式指针转换。这经常是这样。虽然这里没有应用隐式数组对象转换的少数例外:

size_t arr[4], 

    (*parr)[3] = &arr, //taking the address of array

    (&refarr)[3] = arr, //storing reference to array

    sizearrobject = sizeof(arr); //taking the array object size

The above examples will trigger compiler error because of incompatible types on the second and third line.

由于第二行和第三行上的类型不兼容,上面的示例将触发编译器错误。

I'm talking about the cases when arr object isn't automatically converted to something like this:

我在谈论arr对象没有自动转换为这样的情况:

(size_t*)&arr

#3


0  

Well, there are several ways to pass an array to function. You can pass it by pointer an by reference, and there are ways to define or not to define it's size explicitely for both ways.

好吧,有几种方法可以传递一个数组来运行。您可以通过引用通过指针传递它,并且有两种方法可以定义或不明确地定义它的大小。


In your question you compare these 2 ways:

  • Pointer to first element: void f(int *arr)
  • 指向第一个元素的指针:void f(int * arr)

  • Reference to an entire array: void f(int (&arr)[size])
  • 引用整个数组:void f(int(&arr)[size])

You ask why you need to specify size only in one of these cases.

您问为什么只需要在其中一种情况下指定大小。

It looks like you assume that the only difference between them is the fact that one uses pointer and another uses reference. But this statement is incorrect, they have more differences: One is pointer to first element, but second is a reference to an entire array.

看起来你假设它们之间的唯一区别是一个使用指针而另一个使用引用。但是这个语句是不正确的,它们有更多的区别:一个是指向第一个元素的指针,第二个是对整个数组的引用。


You can pass an array by pointer to an entire array:

void f(int (*arr)[size])

Compare it with your example, with passing by refence to an entire array:

将它与您的示例进行比较,将refence传递给整个数组:

void f(int (&arr)[size])    

They are similar, they have similar syntax, they both explicitely define array size.

它们是相似的,它们具有相似的语法,它们都明确地定义了数组大小。


Also, consider this:

void f(int &arr)

It looks like passing a single int by reference, but you can pass an array of unknown size to it.

它看起来像通过引用传递单个int,但您可以传递一个未知大小的数组。

Pointer alternative to it is

指针替代它

void f(int *arr)

You ask why you need to specify array size only in one of those cases. It's because of the syntax you used, not because one is pointer and other is reference.

您问为什么只需要在其中一种情况下指定数组大小。这是因为你使用的语法,不是因为一个是指针而另一个是引用。

As I said, you can use pointer or reference. And you can specify array size or you can allow an array of any size to be used. These two are not connected.

正如我所说,你可以使用指针或引用。您可以指定数组大小,也可以允许使用任何大小的数组。这两个没有连接。

//                     by pointer             by reference
/*   Any size    */    void f(int *arr)       void f(int &arr)
/* Specific size */    void f(int (*arr)[x])  void f(int (&arr)[x])

#1


6  

Because it can, and because checking adds extra safety. The compiler knows the size of the array because you tell it so, right there in the function declaration. And since that information is available, why wouldn't it use it to signal errors in your source code?

因为它可以,并且因为检查增加了额外的安全性。编译器知道数组的大小,因为你告诉它,就在函数声明中。既然该信息可用,为什么不用它来表示源代码中的错误?

The real question is why your last example wouldn't do the same check. This is, unfortunately, another piece of C legacy - you are never passing an array, it always decays into a pointer. The size of the array then becomes irrelevant.

真正的问题是为什么你的最后一个例子不会做同样的检查。不幸的是,这是C遗留的另一部分 - 你永远不会传递一个数组,它总是衰变成一个指针。然后数组的大小变得无关紧要。

Could a check be added? Possibly, but it would be of limited use (since we are all using std::array now - right!?), and because it would undoubtedly break some code. This, for example:

可以添加支票吗?可能,但它的用途有限(因为我们现在都使用std :: array - 对!?),因为它无疑会打破一些代码。这个,例如:

void func (char Values [4]);
func ("x");

This is currently legal, but wouldn't be with an additional check on array size.

这是合法的,但不会额外检查数组大小。

#2


0  

Because there is no odd implicit type change committed by the compiler in the case. Normally when you write:

因为在这种情况下编译器没有提交奇怪的隐式类型更改。通常当你写:

void func(int[4]);

or

void func(void());

The compiler decides to "help" you and translates those into:

编译器决定“帮助”您并将其转换为:

void func(int *);

or

void func(void(*)());

Funny thing though - it wouldn't aid you in such a way when you try returning one of those. Try writing:

有趣的是 - 当你尝试归还其中一个时,它不会以这种方式帮助你。试着写:

int func()[4], func1()();

Ooops - surprise - compiler error.

哎呀 - 惊喜 - 编译错误。

Otherwise arrays are arrays and have constant size which can be acquired by using the sizeof operator.

否则,数组是数组并且具有恒定大小,可以使用sizeof运算符获取。

This however is often forgotten because of the compiler behavior noted above and also because of the implicit pointer conversion applied to objects of array type when such isn't expected. And this is very often. Though here are the few exceptions when no implicit array object conversion is applied:

然而,这经常被遗忘,因为上面提到的编译器行为,并且还因为在不期望这种情况时应用于数组类型的对象的隐式指针转换。这经常是这样。虽然这里没有应用隐式数组对象转换的少数例外:

size_t arr[4], 

    (*parr)[3] = &arr, //taking the address of array

    (&refarr)[3] = arr, //storing reference to array

    sizearrobject = sizeof(arr); //taking the array object size

The above examples will trigger compiler error because of incompatible types on the second and third line.

由于第二行和第三行上的类型不兼容,上面的示例将触发编译器错误。

I'm talking about the cases when arr object isn't automatically converted to something like this:

我在谈论arr对象没有自动转换为这样的情况:

(size_t*)&arr

#3


0  

Well, there are several ways to pass an array to function. You can pass it by pointer an by reference, and there are ways to define or not to define it's size explicitely for both ways.

好吧,有几种方法可以传递一个数组来运行。您可以通过引用通过指针传递它,并且有两种方法可以定义或不明确地定义它的大小。


In your question you compare these 2 ways:

  • Pointer to first element: void f(int *arr)
  • 指向第一个元素的指针:void f(int * arr)

  • Reference to an entire array: void f(int (&arr)[size])
  • 引用整个数组:void f(int(&arr)[size])

You ask why you need to specify size only in one of these cases.

您问为什么只需要在其中一种情况下指定大小。

It looks like you assume that the only difference between them is the fact that one uses pointer and another uses reference. But this statement is incorrect, they have more differences: One is pointer to first element, but second is a reference to an entire array.

看起来你假设它们之间的唯一区别是一个使用指针而另一个使用引用。但是这个语句是不正确的,它们有更多的区别:一个是指向第一个元素的指针,第二个是对整个数组的引用。


You can pass an array by pointer to an entire array:

void f(int (*arr)[size])

Compare it with your example, with passing by refence to an entire array:

将它与您的示例进行比较,将refence传递给整个数组:

void f(int (&arr)[size])    

They are similar, they have similar syntax, they both explicitely define array size.

它们是相似的,它们具有相似的语法,它们都明确地定义了数组大小。


Also, consider this:

void f(int &arr)

It looks like passing a single int by reference, but you can pass an array of unknown size to it.

它看起来像通过引用传递单个int,但您可以传递一个未知大小的数组。

Pointer alternative to it is

指针替代它

void f(int *arr)

You ask why you need to specify array size only in one of those cases. It's because of the syntax you used, not because one is pointer and other is reference.

您问为什么只需要在其中一种情况下指定数组大小。这是因为你使用的语法,不是因为一个是指针而另一个是引用。

As I said, you can use pointer or reference. And you can specify array size or you can allow an array of any size to be used. These two are not connected.

正如我所说,你可以使用指针或引用。您可以指定数组大小,也可以允许使用任何大小的数组。这两个没有连接。

//                     by pointer             by reference
/*   Any size    */    void f(int *arr)       void f(int &arr)
/* Specific size */    void f(int (*arr)[x])  void f(int (&arr)[x])