假设我有一个struct
定义如下:
typedef struct MyStruct {
double a[3];
double b[6];
} MyStruct;
我将结构传递给一个函数来执行一些操作。例如:
void MyFcn(MyStruct *out, const MyStruct *in) {
out->a[2] = in->b[5];
/* do more stuff */
}
如果我想将数组指针MyStruct.a
和MyStruct.b
限定为没有与restrict关键字重叠的内存,是否有任何方法可以做到这一点?
也许大多数编译器会优化假设MyStruct.a
和MyStruct.b
指向连续内存块没有任何混叠,并且没有必要添加限制限定符?我不知道。
我知道我可以简单地让a和b成为指针而不是像这样的数组
typedef struct MyStruct {
double *restrict a;
double *restrict b;
} MyStruct;
但是考虑到数组的大小是已知的,这种方法使调试溢出变得困难,并且不必要地使变量初始化变得复杂(需要动态内存分配或复合字面量和指定初始化器)。
编辑
从下面的注释中,我需要澄清,我想让示例更好地描述问题,而不是将其约束到那个用例中。答案确实澄清了结构成员不能有重叠的内存(这就是联合的作用)。
然而,对于不同的函数输入/输出,问题仍然存在。对于具有不同结构定义的任意数量的函数输入/输出,如果结构之间存在别名数组的可能性,编译器会优化吗?如果没有,如何给出restrict关键字?
"如果我想限定数组指针MyStruct。a和MyStruct。b……"。a
和b
是数组(对于第一个类型定义),而不是指针,也没有明确的"数组指针"——这将是类似于
char a[10];
... &a ....
同样,如果它们隐式地将转换为指针,则它们不能为同一结构体别名。如果需要指向它们的不同指针,可以限定这些restrict
。但是,在示例代码中不使用指向这些数组的指针,因此不需要。
可以别名的指针只有in
和out
。这是一个有意使用的问题。我建议他们实际上不应该这样做,所以你可以将它们限定为restrict
和in
,如果适用的话,还可以加上const
。
Btw:只有指针类型可以被restrict
ed,数组不是指针,但在大多数操作中会衰减到指针。
哦,还有:如果数组的大小是固定的,我同意让字段成为指针是毫无意义的,只是低效的膨胀。
我在restrict
方面没有什么经验。根据研究,这似乎是正确的。所以让这个wiki让所有人都可以修改
将restrict
添加到函数参数中(而不是typedef
)。通过将restrict
添加到指针上,编译器可能会认为只有该指针才能访问/更改它所指向的数据。这允许OP所期望的优化,因为指针不别名彼此的数据。
typedef struct MyStruct {
double a[3];
double b[6];
} MyStruct;
void MyFcn(MyStruct * restrict out, const MyStruct *restrict in);
所以现在MyFcn()
可以假设在使用in
和out
时不会指向相同的数据。调用代码也不应该执行MyFcn(&data, &data)
,因为这会破坏契约,因为调用代码会发送指向重叠内存的指针。
部分restrict
规范
通过限制限定指针访问的对象与该指针具有特殊关联。这个协会,……要求对该对象的所有访问都直接或间接地使用该特定指针的值。
restrict
限定符的预期用途…是促进优化,…C11dr§6.7.3 8引用类型为对象类型的指针类型以外的类型不受限制。§6.7.3 2
翻译人员可以自由地忽略使用
restrict
的任何或所有混叠含义。§6.7.3.1 6
即使一个restrict
参数也可能有意义。
char buf[100];
void foo1(char * restrict p1) {
/* foo1() knows p1 does not overlap global `buf`. */
strcpy(buf, p1);
}