【问题标题】:passing typedef (fixed sized) array by value按值传递 typedef(固定大小)数组
【发布时间】:2011-08-27 09:34:15
【问题描述】:

我很难理解数组的 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* 似乎不匹配。

【问题讨论】:

  • 当人们说“数组衰减到指针”时,他们特别指的是参数a。因此,在您的 if 函数内部,您应该比较 typeid(a) == typeid(char*)。这将显示类型 match。比较 typeid(Char10) == typeid(char*) 没有显示任何内容。这些确实是不同的类型。

标签: c++ arrays typedef


【解决方案1】:

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

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 的数组。并且该数组将不会衰减到 指针,它将通过 reference 传递。

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:这不是他作为第一个版本写的吗?你的函数其实是void fun(char*)
【解决方案2】:

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

C++ 的一个误导性怪癖是你可以看到有一个函数

void fun(char a[10])

既然你不能按值传递数组,而且 C++ 很傻,这实际上是函数

void fun(char* a)

当然,两个输入都愉快地降级为char*

如果 C++ 甚至不让你假装按值接受数组,那就太好了,但是这样很愚蠢.. 继承自 C。

【讨论】:

  • 而 IIRC 它或多或少是从 BCPL 继承而来的(或者它是为了某种与它的兼容性而引入的)。
  • @Tomalak,我相信它不可能是 fun(char*),因为通过引用接收数组只允许 char[10]char[11] 的错误。
  • @iammilind:那里没有任何参考资料。 如果你有一个函数void f(int(&amp;)[3]);,你不能传递一个指针,这是真的。但在这种情况下,你可以。
  • @iammilind:通过引用接收数组是完全不同的鱼。
  • @Tomalak,是第一个被识别的人。不过,我花了一些时间来理解其他答案。
【解决方案3】:

Char10char* 确实是不同的类型..

试试

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

Online demo

PS:

以下声明是等价的

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      对于您的编辑:类型 本身 是不同的,但在 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] 是不同的类型;
      • testchar[10]
      • a 实际上是 char *,因为在函数声明中,数组声明衰减为相应的指针声明。

      由于历史原因,这是一个愚蠢的事情,但我们坚持下去。


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

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

      【讨论】:

      • @iammilind:谢谢。请注意,将数组包装在 struct/class 中将允许您按值传递它(这要归功于 structs 可以按值传递,并且默认构造函数行为是复制成员)。这就是新的std::array 固定大小的低开销容器的工作原理。
      【解决方案6】:

      但是,您可以接受对正确大小的数组的引用,此时编译器反对它。

      【讨论】:

      • 我知道,这就是为什么我明确提到“不通过引用接收”。我想知道为什么按值传递不起作用。
      【解决方案7】:

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

      看起来您希望将数组类型隐藏在 typedef-name 后面可以让您绕过这个限制。它不会。你的

      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的类型,应该将typeid应用到a

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

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

      【讨论】:

      • 为什么 typeids 不匹配?
      • @iammilind :因为Char10char* 是不同的类型。尝试比较我在帖子中提到的achar* 的类型。
      • @iammilind:类型匹配的。请参阅我的答案的第二部分。您在原始代码中比较的内容与手头的问题无关。如果您想查看类型是否匹配,您应该比较typeid(a)
      • 我不明白为什么这个答案值得反对。它重复了其他答案中的一些信息,但看起来你可能与他们同时打字。你提供的信息是完全有效的......
      【解决方案8】:
      struct char10 {
          char c[10];
      };
      
      int foo(char10 param){
      ...
      

      您可以像这样通过值模拟传递固定大小的数组。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-11-08
        • 2011-05-30
        • 1970-01-01
        • 2012-03-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多