如何在结构成员数组中应用限制指针类型关键字?

How to apply the restrict pointer type keyword in struct member arrays?

假设我有一个 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 */
}

如果我想用 restrict 关键字限定数组指针 MyStruct.aMyStruct.b 没有重叠内存,有什么方法可以做到这一点吗?

也许大多数编译器会优化假设 MyStruct.aMyStruct.b 指向连续的内存块而没有任何别名,并且添加 restrict 限定符没有意义?我不知道。

我知道我可以简单地创建 a 和 b 指针而不是像这样的数组

typedef struct MyStruct {
    double *restrict a;
    double *restrict b;
} MyStruct;

但是考虑到数组的大小是已知的,这种方法使得调试溢出变得困难并且不必要地使变量初始化复杂化(需要动态内存分配或复合文字和指定的初始化程序)。

编辑

从下面的评论中,我需要澄清一下,我打算让示例更好地描述问题,而不是将其限制在该用例中。答案确实阐明了结构成员不能有重叠的内存(这就是联合的​​用途)。

但是,对于不同的功能,问题仍然存在inputs/outputs。 对于任意数量的具有不同结构定义的函数inputs/outputs,如果结构之间可能存在别名数组,编译器是否会进行优化?如果不会,如何给出 restrict 关键字?

"If I want to qualify the array pointers MyStruct.a and MyStruct.b ..."。 ab 是数组(对于第一个 typedef),而不是指针和明确的没有 "array pointers" - 就像

char a[10];
... &a ....

此外,如果它们被隐式转换 为指针,则它们不能为相同的结构别名。如果您需要指向它们的不同指针,您可以限定那些 restrict。但是,您没有在示例代码中使用指向这些数组的指针,因此不需要。

唯一可能产生别名的指针是 inout。这是预期用途的问题。我会建议他们实际上不应该,所以你可能会限定他们 restrict 并且 - 可能 in 另外 const 如果适用的话。

顺便说一句:只有指针类型可以是 restricted 并且数组不是指针,但对于大多数操作来说都会衰减到它们。

哦,还有:如果数组的大小是固定的,我同意将字段设为指针是无稽之谈,只会导致效率低下的膨胀。

我对 restrict 没有什么经验,所以有点不知所措。根据研究,这似乎是正确的。所以制作这个wiki供大家修改。


restrict 添加到函数参数(而不是 typedef)。通过将 restrict 添加到指针,编译器可能会假设只有该指针将 access/change 它指向的数据。这允许 OP 所需的优化,因为指针不会相互混淆数据。

typedef struct MyStruct {
    double a[3];
    double b[6];
} MyStruct;

void MyFcn(MyStruct * restrict out, const MyStruct *restrict in);

所以现在 MyFcn() 可以假设在其使用中 inout 不会指向相同的数据。调用代码也不应执行 MyFcn(&data, &data),因为这会破坏合同,因为调用代码会发送指向重叠内存的指针。

一些restrict规格

An object that is accessed through a restrict-qualified pointer has a special association with that pointer. This association, ... requires that all accesses to that object use, directly or indirectly, the value of that particular pointer. The intended use of the restrict qualifier ... is to promote optimization, ... C11dr §6.7.3 8

Types other than pointer types whose referenced type is an object type shall not be restrict-qualified. §6.7.3 2

A translator is free to ignore any or all aliasing implications of uses of 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);  
}