VLA的指针

7

正如你所知,VLA(变长数组)有其优缺点,而在C11中它们是可选的。

我认为将 VLA 设为可选的主要原因是:"栈可能会溢出":

int arr[n]; /* where n = 1024 * 1024 * 1024 */

但是,关于指向VLA的指针呢?

int m, n;

scanf("%d %d", &m, &n);

int (*ptr)[n] = malloc(sizeof(int [m][n]));

在这种情况下,没有炸堆栈的风险,并且我认为它们非常有用。
我的问题是:
委员会是否可以保留对VLA的指针,使得将VLA转换为非指针类型成为可选项?
还是一个事情意味着另一个事情?
(请原谅我的英语不好)

4
虽然这不太政治正确,但我认为将VLA作为可选项的主要原因是微软想假装他们有一个符合标准的编译器。 - StoryTeller - Unslander Monica
4
@PaulOgilvie - nеЅ±е“Ќдє†еЇ№ptrжЊ‡й’€иї›иЎЊжЊ‡й’€з®—жњЇиїђз®—зљ„ж–№ејЏпјЊе®ѓз»ќеЇ№дёЌиѓЅиў«еїЅз•ҐгЂ‚ - StoryTeller - Unslander Monica
3
在数组中,ptr + x必须等于(char*)ptr + x * (sizeof(int[n])),这是通常的指针算术运算。如果行大小是一个常量表达式,那么它和这个公式是一样的。但在这种情况下,行大小不是常量表达式。 - StoryTeller - Unslander Monica
@PaulOgilvie - ptr[i][j] 将寻址一个单独的整数。 - StoryTeller - Unslander Monica
1
一切清楚明白。非常感谢。 - Paul Ogilvie
显示剩余4条评论
1个回答

3
保留指向可变类型的指针需要实现对VLA规范约90%的支持。原因是有效类型规则:
6.5表达式 ¶6 对于访问其存储值的对象,其有效类型是对象的已声明类型(如果有)。如果通过具有非字符类型的类型的lvalue将值存储到没有声明类型的对象中,则该lvalue的类型成为该访问和不修改存储值的后续访问的对象的有效类型。如果使用memcpy或memmove将值复制到没有声明类型的对象中,或者将其作为字符类型的数组复制,则该修改对象的有效类型用于该访问和不修改该值的后续访问是从其中复制值的对象的有效类型(如果有)。对于访问没有声明类型的对象的所有其他访问,对象的有效类型只是用于访问的lvalue的类型。
通过ptr访问malloc分配的内存后,对象的有效类型是VLA类型。因此,实现将需要正确地支持这些语义。唯一可以“可选”的事情是能够声明具有自动存储持续时间的VLA...
int boo[n];

这有点儿可笑。如果一个实现支持动态分配对象的大多数VLA语义,那么它也可以允许将它们声明为具有自动存储期的对象。委员会希望它真正是可选的,这意味着指向VLA类型的指针也必须消失。


我认为这个答案不正确。实现有效的类型规则根本没有任何工作,除了基于非别名进行优化之外,实现者可以省略任何他们喜欢的规则,因为规则适用于符合规范的应用程序而不是实现。另一方面,自动存储 VLAs 必然与低级后端交互。 - R.. GitHub STOP HELPING ICE
@R.. - 这个问题是关于标准的观点。在有效类型规则周围需要被砍掉和修改的规范数量对我来说看起来并不小。当然,实现可以实现任何东西。 - StoryTeller - Unslander Monica
这个引用大多是不相关的,因为您永远无法将数组类型的值存储到对象中,只能将数组元素类型的值存储到数组的元素中。同样,您永远无法访问数组类型的值,只能访问数组的元素。我认为StoryTeller的评论识别出了主要原因。 - Chris Dodd
我认为90%的关于VLAs和实现问题(如额外的复杂性和堆栈管理的不确定性)的抱怨来自于自动VLAs。在我看来,C委员会决定在C23中将VLA类型设为强制性是一个非常好的决定。只有自动VLA将保持可选。 - tstanisl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接