如果我得到了restrict正确的C99 关键字,那么用它来限定一个指针是一个承诺,它引用的数据不会在编译器的后面通过别名修改.
相比之下,我理解const限定符的方式是编译器强制执行的文档,即在人类编写代码的背后不会修改给定对象.编译器可能会得到一个提示作为副作用,但作为程序员,我并不在乎.
以类似的方式,将restrict函数原型中的限定符视为要求用户在调用期间确保独占访问("避免别名"或可能更强的东西)是否合适?它应该用作"文件"吗?
此外,是否有一些事情可以理解,restrict它指向一个指针而不是它指向的数据(如同const)?
编辑:我原本认为这restrict可能会影响线程代码,但这似乎是错误的,所以我从问题中删除对线程的引用,以避免混淆读者.
首先是一些参考.在C99标准说,这大约restrict在第6.7.3:
通过限制限定指针访问的对象与该指针具有特殊关联.此关联在下面的6.7.3.1中定义,要求对该对象的所有访问都直接或间接使用该特定指针的值.117)
restrict限定符(如register存储类)的预期用途是促进优化,并且从构成符合程序的所有预处理转换单元中删除限定符的所有实例不会改变其含义(即,可观察行为).
然后(§6.7.3.1"正式定义restrict"):
让
D是提供指定的对象的装置的一个普通标识符的声明P作为限制限定指针输入T.如果
D出现在块内并且没有存储类extern,则B表示该块.如果D出现在函数定义的参数声明列表中,则B表示关联的块.否则,让我们B表示main块(或在独立环境中在程序启动时调用的任何函数块).在下文中,指针表达式
E被称为基于对象Pif(在B评估之前的执行中的某个序列点E)修改P为指向其先前指向的数组对象的副本将改变其值E.119)注意''based''仅针对具有指针类型的表达式定义.在每次执行期间
B,L设为任何&L基于的 左值P.如果L用于访问X它指定的对象的值,并且X也被修改(通过任何方式),则以下要求适用:T不应该是const限定的.用于访问值的每个其他左值X也应该具有基于的地址P.出于本子条款的目的,每次修改的访问也X应被视为修改P.如果P …
restirct根据C 标准中的正式定义,以下合理的程序似乎具有未定义的行为:
void positive_intcpy(int * restrict q, const int * restrict p, size_t n) {
int *qBgn = q;
const int *pEnd = p + n;
// sequence point S
while (p != pEnd && *p>0) *q++ = *p++;
if (q != qBgn) fprintf(stderr,"Debug: %d.\n",*(q-1)); // undefined behavior!?
}
int main(void) {
int a[6] = {4,3,2,1,0,-1};
int b[3];
positive_intcpy(b,a,3);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该函数将整数从一个数组复制到另一个数组,只要整数为正数。该fprintf调用显示最后复制的正整数(如果有)。p和之间永远不会有任何混叠q。
这真的是UB,还是我的推理错误?
这个问题涉及C99标准的6.7.3.1节。C23最新草案中相关文本没有变化。
q-1我们讨论的是上面标记的指针表达式。是否基于 指定的受限指针对象p? …
gcc 5和clang 3.6都不会在restrict限定符的约束被违反的情况下发出警告,即使在调用时也是如此-Wall.请考虑以下代码片段:
extern void f(char *restrict p, char *restrict q);
void g(char *p)
{
f(p, p);
}
Run Code Online (Sandbox Code Playgroud)
天真地,我希望可以静态地确定违规行为,我期待这-Wall会发出警告.我在某个地方错过了一面旗帜,还是在发出一些我没有看到警告的问题?
我可以看到const volatile合格变量的实际用途,比如
const volatile uint64_t seconds_since_1970;
Run Code Online (Sandbox Code Playgroud)
如果底层硬件机制每秒更新一次值,但该变量在(可能是嵌入式)硬件中不可写.由于所有三个(C11中的四个)类型限定符都被认为是独立的,因此似乎允许所有组合.但我restrict volatile无法想象一个真实的情况,合格的指针才真正有意义:
uint32_t * restrict volatile pointer_to_some_uint32;
Run Code Online (Sandbox Code Playgroud)
[编辑:澄清:两者volatile并restrict适用于指针,而不是指向的对象!]
这是语言所允许的构造,但本身是无用的,还是我错过了一些有价值的应用领域?
我正在做很多矩阵运算,并希望利用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;
}
Run Code Online (Sandbox Code Playgroud)
现在,对于矩阵乘法函数
void mmultiply ( int nrows, int ncols, int **Out, int **A, int **B);
Run Code Online (Sandbox Code Playgroud)
我必须将参数的两个指针限定为受限制吗?这是有效的语法,但我很难确定int *restrict *restrict行为是否有任何不同int **restrict.
那么,指针被正确限制,是通过A[0][col*nrows + row]undefined 访问元素?(即,将编译器假设我仅通过访问矩阵A[col][row]对的值row,使得row < nrow)?或者我必须保持一致吗?
有没有办法定义使用typedef integral/float类型,这意味着没有别名?
相当于(但原始构造)的东西:
template < typename T >
struct restrict { T* __restrict data; };
Run Code Online (Sandbox Code Playgroud)
作为相关的问题,是否可以问gcc它确定别名/指针的别名是什么?
有没有办法告诉C99编译器我要访问给定数组的唯一方法是使用myarray [index]?说这样的话:
int heavy_calcualtions(float* restrict range1, float* restrict range2)
{
float __I promise I won't alias this__ tmpvalues[1000] = {0};
....
heavy calculations using range1, range2 and tmpvalues;
....
}
Run Code Online (Sandbox Code Playgroud)
通过使用restrict我承诺我不会为range1和range2设置别名但是我如何为我的函数内部声明的数组做同样的事情?
请考虑以下代码:
void doesnt_modify(const int *);
int foo(int *n) {
*n = 42;
doesnt_modify(n);
return *n;
}
Run Code Online (Sandbox Code Playgroud)
其中定义对doesnt_modify编译器不可见.因此,它必须假定,doesnt_modify将对象n指向更改并且必须*n在return(最后一行不能被替换return 42;)之前读取.
假设,doesnt_modify不修改*n.我考虑了以下内容以允许优化:
int foo_r(int *n) {
*n = 42;
{ /* New scope is important, I think. */
const int *restrict n_restr = n;
doesnt_modify(n_restr);
return *n_restr;
}
}
Run Code Online (Sandbox Code Playgroud)
这样做的缺点是调用者doesnt_modify必须告诉编译器*n没有被修改,而不是函数本身可以通过其原型告诉编译器.简单地restrict将参数限定doesnt_modify在声明中是不够的,参见 "是顶级volatile还是restrict重要的?".
当与编译gcc -std=c99 …
情况是这样的:
我们从外部源收到了使用 sprintf(如 strcat)的代码。像这样:
char buffer[1024];
sprintf(buffer, "Some text.");
sprintf(buffer, "%s%s", buffer, "Some more text");
sprintf(buffer, "%s%s", buffer, "again more text");
Run Code Online (Sandbox Code Playgroud)
现在,这看起来很奇怪。我们都同意这看起来很奇怪。我要问的不是这个。我们都知道应该用strcat,而且更直接。我问的是除了看起来很奇怪之外,这可能导致的潜在问题。我们在 RHEL6 上运行,并使用 gcc 4.9.3。
感谢您的帮助。