C 如何在每个函数实例上返回大小不同的VLA?
我正在使用一个很好的GCC扩展,它允许我们在结构内部声明VLA。现在我找到了一种通过这种方式(通过值)将VLA传递给函数的方法。我也找到了一种返回一个的方法,但是在一个非常有限的上下文中 本例的功能代码如下:C 如何在每个函数实例上返回大小不同的VLA?,c,arrays,gcc,alloca,gcc-extensions,C,Arrays,Gcc,Alloca,Gcc Extensions,我正在使用一个很好的GCC扩展,它允许我们在结构内部声明VLA。现在我找到了一种通过这种方式(通过值)将VLA传递给函数的方法。我也找到了一种返回一个的方法,但是在一个非常有限的上下文中 本例的功能代码如下: extern void func3() { size_t size; scanf("%zu", &size); struct tx{int _[size];} fn() { struct tx rt; for(s
extern void func3()
{
size_t size;
scanf("%zu", &size);
struct tx{int _[size];} fn()
{
struct tx rt;
for(size_t i=0; i < size; ++i)
scanf("%d", &rt._[i]);
return rt;
}
volatile __typeof__(fn) *pf = fn;
}
换句话说,问号内的类型是什么?或者可能还有其他解决方案(但不使用malloc
)?
这种函数的理论用法在理论上需要另一种类型来存储返回值,因为返回结构的大小对调用方不可用(除非有办法避免这种情况)。但乍一看应该是这样的:
/*???*/ func5()
{
size_t size;
scanf("%zu", &size);
struct {int _[size];} rt;
for(size_t i=0; i < size; ++i)
scanf("%d", &rt._[i]);
return rt; //ok - return the structure
}
如果我们这样做:
/*???*/ func5()
{
size_t size;
scanf("%zu", &size);
struct {int _[size];} rt;
for(size_t i=0; i < size; ++i)
scanf("%d", &rt._[i]);
return rt; //ok - return the structure
}
它不起作用,因为func5
的VM返回类型将取决于它的参数或局部变量。
然而,目前这些都是理论上的,因为我们仍然不能定义这个函数
[…]我希望VLA分配保存在被调用函数中(并且不使用malloc
)
在C程序中,动态内存存储只有两个来源:堆和堆栈
您不想使用第一个,但第二个是自动管理的:当某个函数返回时,您在该函数“内部”分配的任何内容都将“消失”
当然,唯一的例外是返回值。不过,这并没有多大帮助,因为为了留在堆栈上,它的内存(如果通过堆栈返回)被“分配到”函数调用的参数之下。因此,在调用函数之前必须知道它的大小(否则就不知道在哪里存储函数的参数、局部变量等等)
由于“堆栈上的分配”本质上与“以已知字节数推进某个指针”相同,因此这里存在一个矛盾:您希望在函数内部进行分配,但在进入函数之前需要知道分配的数量
这行不通。
如何在每个函数实例上返回大小不同的VLA
返回VLA是一回事,除非通过,否则无法真正执行。(那么退回它的意义是什么)。除非事先确定了调用代码的大小,否则调用代码无法接收它
也许这已经足够接近OP的目标了 使用在已知大小后但在调用
func5()
之前分配的VLA
typedef struct {
size_t size;
int *a;
} va;
void func5(va *p) {
for (size_t i = 0; i < p->size; ++i) {
// error handling not shown
// scanf("%d", &p.a[i]);
p->a[i] = i;
}
}
int main(void) {
// create
size_t size = 5;
// scanf("%zu", &size);
int v[size];
va t = { size, v };
// populate
func5(&t);
// use
for (size_t i = 0; i < size; i++) {
printf("%d\n", t.a[i]);
}
// automatic "free"
return 0;
}
到目前为止,我得到的最接近的方法是利用调用约定(在GCC下工作)-因此我们有一个生成器函数,它将生成数组大小-前半部分和后半部分填充返回的数组:
returnVLAgenerator(vlaout)
char vlaout[];
{
size_t szvla = 3; //calculate vlaout size here
if(vlaout == 0)
return szvla;
while(szvla--) vlaout[szvla] = 'x'; //fill vlaout here
return;
}
然后,如果您希望调用它,您需要生成一个带有函数签名和返回值的戳记,如下所示(示例main函数):
(main())
{
结构{char ar[returnVLAgenerator(0)]}(*returnVLAstamp)()=returnVLAgenerator,vlaOut;
vlaOut=returnVLAstamp();
对于(size_t i=0;i
这里有一些实时的只需让调用方首先分配数组,被调用方只需填写值即可。@user3528438我对其他解决方案不感兴趣。我希望VLA分配保存在被调用的函数中(并且不使用
malloc
)。我试图了解这是如何编码的。像{type_TBD func5();type_TBD y=func5();//使用y}
?你能发布一些使用func5()
结果的理论代码吗?我想说的是,在调用func5()
之前需要知道数组的大小,这样才能声明y=func5()
的y
。你声称希望VLA“保存在被调用的函数中”,但你也要退。这必须创建一个副本,这意味着您需要调用函数中的VLA来接收副本。(无论如何,复制是必要的,因为您无法返回指向局部变量的指针。)因此,唯一的解决方案是@user3528438建议的解决方案,当然,这也不起作用,因为对于不同大小的结构,您需要有不同版本的函数。简而言之,使用malloc。这就是它的用途。如果我能从参数中得到尺寸(与传递VLA的方式相同),也许会。但是,目前这在语法上是不可能的,因为在指定函数返回类型时函数参数不可见。但是也许还有其他的方法谁知道呢。这是正确的方法,尽管你可能应该去掉这个结构,只传递指针和大小。
0
1
2
3
4
returnVLAgenerator(vlaout)
char vlaout[];
{
size_t szvla = 3; //calculate vlaout size here
if(vlaout == 0)
return szvla;
while(szvla--) vlaout[szvla] = 'x'; //fill vlaout here
return;
}
(main())
{
struct { char ar[returnVLAgenerator(0)]}(*returnVLAstamp)() = returnVLAgenerator, vlaOut;
vlaOut = returnVLAstamp();
for(size_t i = 0; i < sizeof(vlaOut.ar); ++i)
printf("%c", vlaOut.ar[i]);
}