请考虑以下代码段:
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);
输出(无编译错误):
2
我无法理解b = a
有效的原因。即使数组可能会衰减为指针,也不应该衰减为常量指针(T * const
)?
答案 0 :(得分: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)有意义。 (术语“衰变”是指参数的转换,而不是参数的调整)。
答案 1 :(得分:8)
引用C11
,章节§6.7.6.3,函数声明符(包括原型)
参数声明为''类型''的数组应调整为''限定指针 输入'',其中类型限定符(如果有)是在
[
和]
内指定的类型限定符。 数组类型推导。 [...]
因此,a
和b
实际上是指针,而不是数组。
没有任何数组类型的任务分配,因此代码没有问题。
答案 2 :(得分:4)
是的,将[]
声明的数组参数调整为const限定指针是有意义的。但是,当建立此行为时,const
不存在。
当开发C语言时,通过传递其地址,或者更具体地说,传递第一个元素的地址来传递数组是有意义的。你当然不想复制整个数组来传递它。传递地址是使被调用函数知道数组的简单方法。 (我们在C ++中看到的引用类型的语义尚未发明。)为了使程序员能够轻松编写代码而不是foo(ArrayA, ArrayB)
,可以编写foo(&Array[0], &ArrayB[0])
而不是void foo(int ArrayA[], int ArrayB[])
,将数组转换为发明了指向其第一个元素的指针。 (由Dennis M. Ritchie根据M.M.和The Development of the C Language,这个参数符号已经存在于C的前身语言B中。)
没关系,你隐藏了转换。但这只是调用函数的地方。在被调用的例程中,正在考虑传递数组的程序员将编写int *ArrayA
。但由于我们实际上是传递指针而不是数组,因此需要将它们更改为int *ArrayB
和int ArrayA[]
。因此,创建了声明为数组的参数自动调整为指针的概念。
正如您所看到的,这使程序员能够为参数赋值,这会更改数组的表观基址。将声明为int * const ArrayA
的参数调整为ArrayA
是有意义的,因此无法更改参数const
的值。然后它会更像一个数组,其地址也无法更改,所以这更符合假装传递数组的目标,即使我们传递地址。
但是,当时const
不存在,所以这是不可能的,没有人想到当时发明class s3(TemplateView):
template_name = 'project/s3.html'
def get_context_data(self, **kwargs):
context = super(s3, self).get_context_data(**kwargs)
aws = boto3.resource('s3')
buckets = aws.buckets.all()
for bucket in buckets:
totalSize = 0
bucketName = bucket.name
createdAt = bucket.creation_date
fileBuckets = boto3.resource('s3').Bucket(bucketName)
for file in fileBuckets.objects.all():
totalSize += file.size
context['buckets'] = buckets
context['bucket'] = buckets
context['createdAt'] = createdAt
context['bucketName'] = bucketName
context['totalSize'] = totalSize
return context
(或者至少做了足够的工作以使其被采用进入语言)。
现在世界上有大量的源代码可用于非const调整。现在更改C语言的规范会导致现有代码出现问题。