【问题标题】:Arguments in a function prototype函数原型中的参数
【发布时间】:2010-07-16 12:02:39
【问题描述】:

我的问题是:当我像这样用 C 语言编写函数原型时:

void foo(int *vector);

同样的做法:

void foo(int vector[MAX_LENGTH]);

对于函数,总是作​​为指针传递?代码是一样的吗? 提前致谢。

【问题讨论】:

    标签: c++ c arrays pointers


    【解决方案1】:

    这很微妙。 C 中的数组不是指针,但 C 不允许将数组作为函数参数传递。因此,当您拥有void foo(int vector[MAX_LENGTH]); 时,实际上您所做的只是告诉其他程序员(以及您未来的自己)该函数需要将MAX_LENGTH 的数组传递给它。编译器不会帮助你。它会默默地将你的数组转换为一个指针。

    This 解释得很好。

    【讨论】:

      【解决方案2】:

      是的,数组类型在传递给函数时会隐式转换为指针类型。

      所以

      void foo(int *a)void foo(int a[]) 是相同的。

      您可以在函数定义中使用sizeof() 运算符轻松检查

      例如

      void foo(int a[])
      {
         std::cout<<sizeof(a); //prints sizeof(int*)
      }
      
      int main()
      {
      
         int a[]={1,2,3,4};
         foo(a);
      }
      

      EXTRA(在函数内打印数组的大小)

      [C++ Only]

       template<typename T,size_t n>
       void size_of_array(T (&a)[n]) //Array passed by reference. Template argument deduction 
       {
          std::cout<<sizeof(a); //prints sizeof(n*sizeof(int))
       }
      
       int main()
       {
            int a[]={1,2,3,4,5};
            size_of_array(a);
       }
      

      【讨论】:

      • 对于 C++,一个更好的演示方法是 puts(typeid(a).name())
      【解决方案3】:

      这是 C 语言的粗糙边缘之一。两个看起来完全相同(但名称不同)的声明,一个在原型中,一个作为堆栈变量,导致声明两种不同类型的变量。

      void foo(int A[10]) {
         int B[10];    
      }
      

      foo 的范围内,A指向 int 的指针Bint 类型的十个元素组成的数组。正如其他人所提到的,即使它们使用sizeof 计算的大小也不同。

      C++ 继承了该规则,因此对于您的示例代码,两个函数的原型应该相同。

      C99 通过引入新的关键字 static 使问题更加复杂化;-)

      void foo(int A[static 10]) {
         int B[10];    
      }
      

      这不会改变从内部看到AB 的规则,但会向调用方提供预期数组元素数量的信息。目前 gcc 接受这种新语法并忽略此信息。

      【讨论】:

      • 如果我没记错的话,与 static 的唯一区别是它变成了 U.B.让调用者将指针传递给具有较少元素的数组,即使该函数实际上并未尝试取消引用它们 - 我猜这允许编译器将其实现为小型数组的按值传递(如果它看到)该数组在函数中没有发生变异,并且不可能通过别名进行变异。
      • @Pavel:我检查了规范,看起来它是命令式的,而不是 U.B.,他们使用动词 shallmust。在 gcc 文档中,他们指出这是他们仍然不符合 C99 的点之一。另外我不认为这允许按值传递,因为它允许将指针传递给比指定更大的数组。
      • "如果违反了出现在约束之外的 ''shall'' 或 ''shall not'' 要求,则行为未定义。未定义的行为在本国际标准中由以下词语指示''未定义的行为''或省略任何明确的行为定义。这三者在强调方面没有区别;它们都描述了“未定义的行为”。”
      • 切片后仍然可以传值。是的,这仍然是一个延伸......我认为标准中这些限制的全部意义在于明确指出,对于a[static n],编译器生成的输出最多可以访问an 的第一个元素,甚至如果源代码没有。除了尝试按值传递之外,我想不出任何可能有用的情况。
      • 这是static的基本原理:groups.google.com/group/comp.std.c/browse_thread/thread/…“目的是允许使用一些DSP和RISC甚至一些CISC处理器现在拥有的数据预取指令。生成的代码用于接收这样一个数组作为参数的函数可以包括一个预取指令,以便在需要之前将数组的内容移动到缓存或其他快速访问缓冲区中”。此外,它还用作“非空”约束,还允许进行一些潜在的优化(例如free)。
      【解决方案4】:

      没有什么可以通过的! [] 约束让编译器做更多的检查。

      【讨论】:

      • 大多数 C 编译器实际上不会进行这些检查。
      • 事实上,任何试图根据[] 中指定的函数参数边界检查数组长度的编译器都是不符合标准的。标准对此非常清楚 - [] 只是变成了 * - 所以像 void foo(int a[2]) { a[0]++; } ... int x; foo(&amp;x); 这样的东西具有明确定义的含义,并且会在其中插入任何检查的编译器不符合规范。
      • 插入支票?我说检查。意思是,在编译时!很抱歉造成混乱
      猜你喜欢
      • 2014-02-13
      • 1970-01-01
      • 2013-12-29
      • 2015-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多