iBu*_*Bug 5 c arrays variable-assignment function-parameter
请考虑以下代码段:
void foo(int a[], int b[]){
static_assert(sizeof(a) == sizeof(int*));
static_assert(sizeof(b) == sizeof(int*));
b = a;
printf("%d", b[1]);
assert(a == b); // This also works!
}
int a[3] = {[1] = 2}, b[1];
foo(a, b);
Run Code Online (Sandbox Code Playgroud)
输出(无编译错误):
2
Run Code Online (Sandbox Code Playgroud)
我无法理解为什么b = a有效.即使数组可能衰减到指针,它们是否应该衰减到const指针(T * const)?
M.M*_*M.M 10
无法分配数组.foo函数中没有数组.int a[]函数参数列表中的语法意味着声明a具有"指向int"的类型.行为与代码完全相同void foo(int *a, int *b).(C11 6.7.6.3/7)
将一个指针指向另一个指针是有效的.结果是两个指针指向同一位置.
即使数组可能衰减到指针,它们不应该衰减为常量指针(T*const)吗?
由数组"衰减"产生的指针是一个右值.所述const限定词仅用于左值(C11 6.7.3/4)有意义.(术语"衰变"是指参数的转换,而不是参数的调整).
引用C11,章节§6.7.6.3,函数声明符(包括原型)
一个参数作为的声明""类型的阵列"",应调整至""合格指针为类型"",其中类型限定符(如果有的话)的那些内的指定
[和]该阵列类型的推导.[...]
所以,a和b实际上是指针,不是数组.
这里没有任何数组类型的赋值,因此代码没有问题.
是的,对于用以下方式声明的数组参数是有意义的[]为 const 限定指针是有意义的。然而,const这种行为建立时并不存在。
当 C 语言正在开发时,通过传递数组的地址,或者更具体地说,第一个元素的地址来传递数组是有意义的。您当然不想复制整个数组来传递它。传递地址是一种让被调用函数知道数组的简单方法。(我们在 C++ 中看到的引用类型的语义尚未被发明。)为了让程序员更容易,以便他们可以编写foo(ArrayA, ArrayB)而不是foo(&Array[0], &ArrayB[0]),发明了将数组转换为指向其第一个元素的指针的机制。(每MM和C语言的发展,这种参数表示法已经存在于 C\xe2\x80\x99 的前身语言 B 中。)
没关系,您已经隐藏了转换。但这只是调用该函数的地方。在被调用的例程中,考虑传递数组的程序员将编写void foo(int ArrayA[], int ArrayB[]). 但由于我们实际上传递的是指针,而不是数组,因此需要将它们更改int *ArrayA为int *ArrayB。于是就产生了声明为数组的参数自动调整为指针的概念。
正如您所观察到的,这使得程序员能够为参数赋值,从而改变了数组的表观基地址。将声明为的参数调整为 是有意义int ArrayA[]的int * const ArrayA,这样参数的值ArrayA就无法更改。那么它的行为就更像一个数组,其地址也无法更改,因此这更符合假装传递数组的目标,即使我们正在传递地址。
然而,当时const还不存在,所以这是不可能的,const当时没有人想到发明(或者至少做了足够的工作以使其被采用到语言中)。
现在世界上有大量的源代码适用于非常量调整。现在改变C语言的规范将会导致现有代码出现问题。
\n