【发布时间】:2010-07-16 12:02:39
【问题描述】:
我的问题是:当我像这样用 C 语言编写函数原型时:
void foo(int *vector);
同样的做法:
void foo(int vector[MAX_LENGTH]);
对于函数,总是作为指针传递?代码是一样的吗? 提前致谢。
【问题讨论】:
我的问题是:当我像这样用 C 语言编写函数原型时:
void foo(int *vector);
同样的做法:
void foo(int vector[MAX_LENGTH]);
对于函数,总是作为指针传递?代码是一样的吗? 提前致谢。
【问题讨论】:
这很微妙。 C 中的数组不是指针,但 C 不允许将数组作为函数参数传递。因此,当您拥有void foo(int vector[MAX_LENGTH]); 时,实际上您所做的只是告诉其他程序员(以及您未来的自己)该函数需要将MAX_LENGTH 的数组传递给它。编译器不会帮助你。它会默默地将你的数组转换为一个指针。
This 解释得很好。
【讨论】:
是的,数组类型在传递给函数时会隐式转换为指针类型。
所以
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);
}
【讨论】:
puts(typeid(a).name())。
这是 C 语言的粗糙边缘之一。两个看起来完全相同(但名称不同)的声明,一个在原型中,一个作为堆栈变量,导致声明两种不同类型的变量。
void foo(int A[10]) {
int B[10];
}
在foo 的范围内,A 是指向 int 的指针,B 是由int 类型的十个元素组成的数组。正如其他人所提到的,即使它们使用sizeof 计算的大小也不同。
C++ 继承了该规则,因此对于您的示例代码,两个函数的原型应该相同。
C99 通过引入新的关键字 static 使问题更加复杂化;-)
void foo(int A[static 10]) {
int B[10];
}
这不会改变从内部看到A 和B 的规则,但会向调用方提供预期数组元素数量的信息。目前 gcc 接受这种新语法并忽略此信息。
【讨论】:
static 的唯一区别是它变成了 U.B.让调用者将指针传递给具有较少元素的数组,即使该函数实际上并未尝试取消引用它们 - 我猜这允许编译器将其实现为小型数组的按值传递(如果它看到)该数组在函数中没有发生变异,并且不可能通过别名进行变异。
a[static n],编译器生成的输出最多可以访问a 的n 的第一个元素,甚至如果源代码没有。除了尝试按值传递之外,我想不出任何可能有用的情况。
static的基本原理:groups.google.com/group/comp.std.c/browse_thread/thread/…“目的是允许使用一些DSP和RISC甚至一些CISC处理器现在拥有的数据预取指令。生成的代码用于接收这样一个数组作为参数的函数可以包括一个预取指令,以便在需要之前将数组的内容移动到缓存或其他快速访问缓冲区中”。此外,它还用作“非空”约束,还允许进行一些潜在的优化(例如free)。
没有什么可以通过的! [] 约束让编译器做更多的检查。
【讨论】:
[] 中指定的函数参数边界检查数组长度的编译器都是不符合标准的。标准对此非常清楚 - [] 只是变成了 * - 所以像 void foo(int a[2]) { a[0]++; } ... int x; foo(&x); 这样的东西具有明确定义的含义,并且会在其中插入任何检查的编译器不符合规范。