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 执行相同的操作,则行为将是未定义的。