按值传递 typedef(固定大小)数组

5

我很难理解数组的typedef模式。

typedef char Char10[10];
void fun (Char10 a)  // not passing reference (interested in pass by value)
{
  if(typeid(Char10) == typeid(char*))
    throw 0;  // <--- never happens
}

int main ()
{
  char a[10];  fun(a);  // ok
  char b[11];  fun(b);  // why works ?
}

为什么fun()可以接受不同大小的数组?char[10]char[11]不是不同的类型吗? 编辑:对于那些说它会衰变为指针的人,请看我的修改后的代码。char[10]char*似乎不匹配。

4
当人们说“数组衰变为指针”时,他们特别是指参数 a。因此,在函数内部的 if 中,您应该比较 typeid(a) == typeid(char*),这将显示类型匹配。比较 typeid(Char10) == typeid(char*) 不会显示任何内容。这些确实是不同的类型。 - AnT stands with Russia
8个回答

24

在这两种情况下,数组 衰减 为指针类型,因此你的函数实际上是这样的:

void fun (char *a); 

这就是为什么它能工作。

我想强调一下,void fun(char*)void fun(char[10]) 是完全相同的。其中的 10 完全没有任何区别。实际上,10 如此不重要和无用,以至于你甚至可以完全省略它:

void fun (char a[]); //exactly same as `char*` or `char[10]`.

这意味着,所有以下函数声明是完全相同的

void fun(char a[10]);   
void fun(char a[]);  //10 is unimportant in the above declaration
void fun(char *a);   //same as above two declarations!

希望这能解决您的疑惑。


然而,如果您写下以下内容:

void fun (Char10 & a) ; //note &

那么,实际上它是这样的:

void fun (char (&a)[10]) ; //equivalent!

那么 fun(b) 将无法编译通过,因为现在 fun 只接受大小为10的数组。并且该数组不会退化为指针,它将通过引用传递。

char a[10], b[11];
char *c=new char[10];
fun(a); //okay
fun(b); //error - type mismatch due to size of the array
fun(c); //error - type mismatch due to c being pointer.

我知道,这就是为什么我明确提到了“不通过引用接收”。我想知道为什么按值传递不起作用。请查看我的编辑过的帖子。 - iammilind
@iammilind:请再看一下我的回答! - Nawaz
1
@iammilind:那不是他写的第一个版本吗?你的函数实际上是 void fun(char*) - Xeo

9

你是对的,它们是不同类型。

这是C++的一个误导性特性,你可能会被认为有一个函数。

void fun(char a[10])

由于你不能通过值传递数组,而且C++很傻,所以这实际上是函数:

void fun(char* a)

当然,这两个输入都可以愉快地转换为char*

如果C++不允许你通过值来接受数组,那就太好了,但它是从C继承而来的,所以在这方面有些愚蠢。


如果我没记错的话,它更多地是从BCPL继承而来的(或者为了某种兼容性而引入的)。 - Matteo Italia
@Tomalak,我相信它不能是fun(char*),因为通过引用接收数组仅允许 char[10],对于 char[11] 会出错。 - iammilind
@iammilind: 那里并没有关于引用的问题。如果你有一个函数 void f(int(&)[3]);,那么你不能传递一个指针,这是正确的。但在这种情况下,你可以。 - etarion
@iammilind:通过引用接收数组完全是另一回事。 - Lightness Races in Orbit
@Tomalak,作为第一个识别的人。虽然我花了一些时间通过其他答案来理解。 - iammilind

4

Char10char*确实是不同的类型。

尝试:

if(typeid(a) == typeid(char*))
    throw 0;  // happens

在线演示

附言:

以下声明等价。

void fun(Char10 a);
void fun(char a[]);
void fun(char *a);

2

针对您的编辑:类型本身是不同的,但在C++中,您不能将数组作为参数按值传递给函数,当您将其用作函数参数时,数组类型会转化为相应的指针类型。

#include <iostream>
#include <typeinfo>

using namespace std;

typedef char Char10[10];
void fun (Char10 a) // <-- actually Char10 here is read as char *
{
    Char10 test;
    cout<<(typeid(Char10) == typeid(char*))<<'\n'
        <<(typeid(Char10) == typeid(test))<<'\n'
        <<(typeid(char *) == typeid(a))<<endl;
}

int main ()
{
  char b[11];  fun(b);  // why works ?
}

这会输出:
0
1
1

因为

  • char *char[10] 是不同的类型;
  • test 是一个 char[10]
  • a 实际上是一个 char *,因为在函数声明中,数组声明会退化为相应的指针声明。

这是一件因历史原因存在的愚蠢之事,但我们被困在其中。


在标准中找到:第 §8.3.5 ¶3 段:

确定每个参数的类型后,任何类型为“T 数组”或“返回 T 的函数”的参数都会调整为相应的“T 指针”或“返回 T 的函数指针”,分别。


@iammilind:谢谢。请注意,将数组包装在struct/class中将使您可以通过值传递它(由于struct可以通过值传递,并且默认构造函数行为是复制成员)。这就是新的std::array固定大小低开销容器的工作方式。 - Matteo Italia

2

当你收到一个数组参数时,编译器将其理解为指向数组第一个元素的指针。在运行时,不同大小的数组之间没有区别。这就是为什么你需要知道你正在使用的大小,以避免访问不属于你的程序的内存。


1

在C和C++中,你不能通过值传递数组。C/C++中的数组是不可复制的,因此无论你做什么,都无法实现数组类型的“按值传递”语义。

看起来你希望通过typedef名称隐藏数组类型来解决这个限制。但这是行不通的。

void fun(Char10 a)

声明等同于

void fun(char a[10])

声明, 这与

是等价的
void fun(char a[])

void fun(char *a)

所以,你的a参数具有指针类型。当你像这样传递一个数组时

char a[10]; fun(a); 

你只是简单地传递了一个指向数组第一个元素的 char * 指针。数组的大小并不重要,这就是为什么你能够使用这种方法传递不同大小的数组。

fun 函数内部,如果你想分析参数 a 的类型,你应该对 a 应用 typeid

if(typeid(a) == typeid(char*))
  throw 0;

这将向您展示类型匹配。我不清楚为什么您直接将typeid应用于Char10,以及您希望从中得出什么。数组类型在函数参数声明中会衰减为指针类型,但它们不会在typed运算符中衰减为指针类型,这意味着您的if版本与参数声明中发生的事情完全无关。

为什么类型ID不匹配? - iammilind
@iammilind:因为Char10char*是不同的类型。尝试按照我在帖子中提到的那样比较achar*的类型。 - Prasoon Saurav
@iammilind:类型*匹配。请查看我的答案的第二部分。您在原始代码中进行比较与所讨论的问题没有关系。如果您想查看类型是否匹配,应该比较typeid(a) - AnT stands with Russia
我不明白为什么这个答案应该被踩。虽然它重复了其他答案中的一些信息,但看起来你可能与他们同时在输入。你提供的信息是完全有效的... - monkey0506

1

然而,您可以接受正确大小的数组的引用,此时编译器将会对其提出异议。


我知道,这就是为什么我明确提到了“不通过引用接收”。我想知道为什么按值传递不起作用。 - iammilind

1
struct char10 {
    char c[10];
};

int foo(char10 param){
...

您可以通过以下方式模拟按值传递固定大小的数组。

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