C 为什么不';指向VLA函数参数的t指针会自动推断其大小,目前是否有良好的使用方法?
据我所知,每个VLA都有一个大小的隐藏变量,可以通过C 为什么不';指向VLA函数参数的t指针会自动推断其大小,目前是否有良好的使用方法?,c,language-lawyer,c11,C,Language Lawyer,C11,据我所知,每个VLA都有一个大小的隐藏变量,可以通过sizeof运算符“获取”该值。这里我没有得到的是指向函数参数中使用的VLA的指针——为什么它们的大小不能自动推导并存储在这个隐藏变量中——为什么我们应该显式地提供它。在这种情况下,既然我们已经有了“指向未知大小数组的指针”类型,为什么还要使用它呢 我的意思是: void func(size_t, int (*)[*]); //function accepting pointer to VLA void func_1(size_t, int
sizeof
运算符“获取”该值。这里我没有得到的是指向函数参数中使用的VLA的指针——为什么它们的大小不能自动推导并存储在这个隐藏变量中——为什么我们应该显式地提供它。在这种情况下,既然我们已经有了“指向未知大小数组的指针”类型,为什么还要使用它呢
我的意思是:
void func(size_t, int (*)[*]); //function accepting pointer to VLA
void func_1(size_t, int (*)[]); //function accepting pointer to array of unknown bound
void func(size_t sz, int (*parr)[sz]) //implementation of 'func'
{
printf("%lu", sizeof(*parr) / sizeof(int));
printf("%lu", sz);
}
void func_1(size_t sz, int(*parr)[]) //implementation of 'func_1'
{
//printf("%lu", sizeof(*parr) / sizeof(int)); //error: invalid application of 'sizeof' to an incomplete type 'int []'
printf("%lu", sz);
}
如我所见,使用'func'而不是'func_1'的唯一好处是'sizeof'运算符将返回初始值'sz'的副本
上述功能的示例用法:
int main()
{
size_t sz = 3;
int arr[sz];
func(sizeof(arr) / sizeof(int), &arr);
func_1(sizeof(arr) / sizeof(int), &arr);
return 0;
}
为什么不能隐式指定指向VLA参数的指针的大小?这至少可以很好地利用语法:
void func(int (*parr)[*]) // size copied from function argument
{
printf("%lu", sizeof(*parr) / sizeof(int));
printf("%lu", sz);
}
然后像这样调用函数:
int main()
{
size_t sz = 3;
int arr[sz];
func(&arr);
return 0;
}
将导致值为“3”的数组隐藏大小变量作为隐藏参数传递给“func”,创建类似于使用当前语法实例化先前的“func”并使用“sizeof”运算符传递数组的代码
如果您对将建议的语法编译成任何叮当作响的编译器有足够的兴趣,您将得到一个复活节彩蛋(;。可变长度数组的长度只在本地知道(必须是这样,以便堆栈分配存储并提供
sizeof
语义)。当它传递给函数时,它只是一个常规数组类型,因此必须显式传递大小。在一个令人讨厌的乱七八糟的问题中,几十年前就应该被废除,但现在有太多代码需要依赖,C编译器认为数组类型的所有函数参数都等同于poin的参数无论是否指定了数组大小,都要指定元素类型
定义一种语法可能不会有任何主要的技术困难,通过这种语法,函数可以传递任意大小的数组,并自动知道它们有多大。不幸的是:
第二个问题可以通过添加一种语法来解决,该语法将指针/长度组合转换为“已知大小的数组”,该数组可以传递给接受此类内容的方法。然而,前一个问题可能无法解决,除非或直到C被一种不关注指针“优化”的语言取代甚至不再相关。可变长度数组(VLA)的大小与类型相关,而与对象无关 例如,假设:
size_t n = 41;
int vla[n+1];
printf("sizeof vla = %zu\n", sizeof vla);
编译器创建一个初始化为n+1
的匿名对象,我称之为\u anon
,并定义一个类型int[\u anon]
,它是数组对象vla
的类型(请注意,以后更改n
的值不会更改\u anon
的值或vla类型的大小)
你也可以写:
size_t n = 41;
typedef int vla_t[n+1];
vla_t vla;
将sizeof
应用于表达式(在本例中,该表达式恰好是一个对象名)会生成该表达式类型的大小
在
func
内部,vla
的类型不可见,因此无法获取其大小。parr
是指向未指定大小的int
数组的指针。类型int[]
(未指定大小的数组)和int[n+1]
(长度为n+1
的可变长度数组)`兼容,但不是同一类型。没有任何“隐藏变量”。sizeof
在编译时被计算。请参见抱歉,但这种情况不同。这不是普通类型,而是VA类型。编辑后我会再说一遍。调用func(&arr);
将不知道有多少数组元素,甚至不知道它是数组还是单个值。没有隐藏的大小,它只是一个指针。但是'sizeof(arr)是的。在“VA”的情况下,大部分实现都是通过隐藏变量完成的。我感觉你不知道类型系统是什么。我现在就停止评论,希望能遇到一些受过更好教育的C程序员(他们读过ISO标准-best).那么VLA参数类型的建议是什么呢?就目前而言,我看不出它们有什么好的用途。它非常有限……它允许函数声明对其VLA类型的长度避而不谈,同时允许定义根据实际参数指定它。它本身不会导致传递大小。因此基本上它只允许n某个值的隐式副本,稍后可由sizeof运算符接收。这是我的看法。是的。我的理解是,该功能的设计旨在避免以任何方式使ABI复杂化。从调用约定的角度来看,VLA参数是非实体的。唯一需要的支持是其函数的代码生成elf@Sneftel我不太明白你的意思?更重要的是,为什么我们要使用指向VLA的指针而不是指向未知大小数组的指针?@FISOCPP:int*[]类型的参数相当于类型int**
;在*
周围添加括号不会改变这一点。虽然可以声明VLA变量,理论上也可以声明VLA参数,但没有VLA类型,也没有指向VLA的指针(与指向其第一个元素的指针不同)不,是的。来吧-ISO书呆子-你在哪里?给定int n=42;
,int[n]
是VLA类型,而int(*)[n]
是指针-