13

我正在做很多矩阵运算,并希望利用 C99 的restrict指针限定符。

我想将我的矩阵设置为指向指针的指针,以便于下标,如下所示:

int **A = malloc (ncols * sizeof(int *));
A[0] = malloc (nrows * ncols * sizof(int));
for (int i=1; i < ncols; i++) {
    A[i] = A[0] + i*nrows;
}

现在,对于矩阵乘法函数

void mmultiply ( int nrows, int ncols, int **Out, int **A, int **B);

我必须将参数的两个指针都限定为受限吗?这是有效的语法,但我很难确定int *restrict *restrict其行为是否与int **restrict.

那么,在正确限制指针的情况下,是否通过A[0][col*nrows + row]undefined 访问元素?(即,编译器是否会假设我通过这样A[col][row]的值访问矩阵)?还是我必须保持一致?rowrow < nrow

4

3 回答 3

4

对于第一个问题,“是”,如果您同时使用这两个限定符,这将意味着不同restrict,特别是指针也不会被别名。至于它是否有任何区别:理论上是的,在实践中,这取决于优化器。

对于第二个问题“是”,它将假定通过行指针访问的任何内容都只能通过行指针访问。

你也可以扔进const去。

最后,如果这是 -O2、-O3 或 -Os 处的 gcc,则编译器已经在根据类型进行别名分析。我相信其他编译器也会这样做。这意味着已经理解了限制指针与整数,只留下可能相互存储的数组。

总之,优化器将假定指针没有被存储为整数,并且它知道在循环期间它没有进行任何指针写入。

所以你可能会得到相同的代码,只有一个限制。

于 2009-09-20T00:23:03.057 回答
2

外部(第二个)限制告诉编译器没有指针数组(A、B 和 out)别名。内部(第一个)限制告诉编译器没有整数数组(由指针数组的元素指向)别名。

如果您同时访问 A[0][col*nrows + row] 和 A[col][row] 那么您违反了内部限制,因此事情可能会中断。

于 2009-09-20T00:09:01.803 回答
2

int **restrict仅断言 Out、A 和 B 寻址的内存不重叠(除非 A 和 B 可以重叠,假设您的函数不修改其中任何一个)。这意味着指针数组。它没有断言 Out、A 和 B 指向的内存内容的任何内容。 n1124 中的脚注 117 说:

如果标识符 p 具有类型 (int **restrict),则指针表达式 p 和 p+1 基于 p 指定的受限指针对象,但指针表达式 *p 和 p[1] 不是。

与 类比const,我怀疑使用restrict两次限定会断言您想要什么,即数组中的值都没有指向重叠的内存。但是阅读标准,我无法向自己证明它确实如此。我认为“让 D 是一个普通标识符的声明,它提供了一种将对象 P 指定为指向类型 T 的限制限定指针的方法”确实意味着对于int *restrict *restrict A,那么 A[0] 和 A[1] 是对象指定为指向 int 的限制限定指针。但这是相当沉重的法律术语。

请注意,我不知道您的编译器是否真的会利用这些知识做任何事情。显然可以,这是是否实施的问题。

所以我真的不知道你在传统的 C 2-D 数组中获得了什么,你只需在其中 allocaterows * cols * sizeof(int)和 index with A[cols*row + col]。那么你显然只需要使用一次限制,并且任何执行任何操作的编译器都restrict能够在写入到 Out 的过程中重新排序从 A 和 B 的读取。没有restrict,当然,它不能,所以通过做你正在做的事情,你把自己置于编译器的怜悯之下。如果它不能处理双重限制,只有单一限制的情况,那么你的双重间接已经花费了你的优化。

乍一看,乘法可能比额外的指针间接更快。您显然关心性能,否则您根本不会使用限制,因此在进行此更改之前,我会相当仔细地测试性能(在您关心的所有编译器上),以便语法稍微好一点,而不必记住有多少每次访问时数组中都有列。

是否通过 A[0][col*nrows + row] 访问元素未定义?

是的,如果元素被其中一种访问修改,因为这使得 A[0] 成为内存的别名,也通过 A[col] 访问。如果只有 A 和 B 是限制限定的指针,那很好,但如果 A[0] 和 A[col] 是,则不是。

我假设你没有在这个函数中修改 A,所以实际上这个别名很好。但是,如果您对 Out 执行相同的操作,则行为将是未定义的。

于 2009-09-20T00:30:43.167 回答