最近在看C语言核心技术这本书。看到指针。有一些概念不太清楚!
restrict是用来优化的,是C99新加的关键字,估计流行的编译器还不
支持
。
你可以把restrict删除,然后直接编译,运行结果一样的,最多慢一点。
和const用法差不多,但是意思不一样。
C/C++灵活的语法限制了它们的计算速度。譬如这个
函数
:
void func(const int* values1,const int* values2,int* values3,int valueNum)
{
for(int i=0;i<valueNum;++i)
values3[i]+=value1[i]*values2[i];
}
如果CPU支持矩阵运算,譬如可以用一条指令来计算两个向量的积,上面这个函数就可以被优化为一条指令。但是,事实上是不可能的。因为这种指令可能是:
a.先读入两个向量的所有值到寄存器
b.计算,将结果寄存器里。
c.写回计算结果。
所以,上面这个不能被优化,因为编译器不能保证values1和values2的内容在这个循环里不改变。因为,虽然有const修饰,但是这个const是语法/语义上的,而不一定是真实的。譬如,有个人这样调用这个函数:
int a[10];
func(a,a,a,10);
这样,如果用那个特殊指令去优化,可能造成实际结果和预计结果不一样。所以,不能优化。
但是如果你把前两个指针声明为restrict,就表示,在这个函数内,这两个指针的值得任何改变,都是通过这两个指针进行的。这样,编译器就可以自由优化了。从而使C可以达到Fortran一样的运算效率。
restrict的定义是It can be applied only to pointers, and it indicates that a pointer is the sole initial means of accessing a data object.
我不知道确切应该怎么翻译,大意是restrict只对指针有用,它声明一个指针是唯一初始化访问一个数据对象。
比如,按照书上的例子,
int ar[ 10 ];
int * restrict restar = ( int * ) malloc( 10 * sizeof ( int )); int * par = ar;
for (n = 0 ; n < 10 ; n ++ )
... { par[n] += 5;
restar[n] += 5;
ar[n] *= 2;
par[n] += 3;
restar[n] += 3;
}
![]()
restar指针是restrict类型,par指针就不是,因为par即没有初始化也不是唯一访问ar数组的变量。
那么,上面的程序,因为restar是唯一反问数据块的指针,所以编译器可以对它优化为一条语句,
restar[n] += 8; /* ok replacement */
而par就不可以,
par[n] += 8; / * gives wrong answer */
void
f (
const
int
*
pci,
int
*
pi;);
//
is *pci immutable?
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
...
{
(*pi)+=1; // not necessarily: n is incremented by 1
*pi = (*pci) + 2; // n is incremented by 2
}
int
n;
f(
&
n,
&
n);
In this example, both pci and pi point to the same variable, n. You can't change n's value through pci but you can change it using pi. Therefore, the compiler isn't allowed to optimize memory access for *pci by preloading n's value. In this example, the compiler indeed shouldn't preload n because its value changes three times during the execution of f(). However, there are situations in which a variable is accessed only through a single pointer. For example:
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
The name of the file and its open mode are accessed through unique pointers in fopen(). Therefore, it's possible to preload the values to which the pointers are bound. Indeed, the C99 standard revised the prototype of the function fopen() to the following:
/* new declaration of fopen() in <stdio.h> */
FILE
*
fopen(
const
char
*
restrict filename,
const
char
*
restrict mode);
Similar changes were applied to the entire standard C library: printf(), strcpy() and many other functions now take restrict pointers:
C++ doesn't support restrict yet. However, since many C++ compilers are also C compilers, it's likely that this feature will be added to most C++ compilers too.
所以,在没有restrict的时候,编译器需要考虑上面的出错情况,而无法优化程序。
restrict也可以用在函数的指针参数前面,它表示在函数里没有其他标识符会修改指针所指的数据块,编译器可以优化函数。
restrict是C99版新增加的关键字! 如下:
由 restrict 修饰的指针主要用于函数形参,或指向由 malloc() 分配的内存空间。restrict 数据类型不改变程序的语义。 编译器能通过作出 restrict 修饰的指针是存取对象的唯一方法的假设,更好地优化某些类型的例程。
[典型例子] memcpy() 在 C99 中,restrict 可明确用于 memcpy() 的原型,而在 C89 中必须进行解释。 void *memcpy (void *restrict str1, const void *restrict str2, size_t size); /* 通过使用 restrict 修饰 str1 和 str2 来保证它们指向不重叠的对象 */
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedSubBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif)
One of the new features in the recently approved C standard C99, is the restrict pointer qualifier. This qualifier can be applied to a data pointer to indicate that, during the scope of that pointer declaration, all data accessed through it will be accessed only through that pointer but not through any other pointer. The 'restrict' keyword thus enables the compiler to perform certain optimizations based on the premise that a given object cannot be changed through another pointer. Now you're probably asking yourself, "doesn't const already guarantee that?" No, it doesn't. The qualifier const ensures that a variable cannot be changed through a particular pointer. However, it's still possible to change the variable through a different pointer. For example:
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->
void f (const int* pci, int *pi;); // is *pci immutable?
{
(*pi)+=1; // not necessarily: n is incremented by 1
*pi = (*pci) + 2; // n is incremented by 2
}
int n;
f( &n, &n);//增加restrict关键字是因为这里会出问题,
//如果对两个参数都使用了restrict关键字,那么这里编译时会报错,因为一
//个地址可以通过两个指针访问了
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->
In this example, both pci and pi point to the same variable, n. You can't change n's value through pci but you can change it using pi. Therefore, the compiler isn't allowed to optimize memory access for *pci by preloading n's value. In this example, the compiler indeed shouldn't preload n because its value changes three times during the execution of f(). However, there are situations in which a variable is accessed only through a single pointer. For example:
FILE *fopen(const char * filename, const char * mode);
<!--[if !supportLineBreakNewLine]-->
<!--[endif]-->
The name of the file and its open mode are accessed through unique pointers in fopen(). Therefore, it's possible to preload the values to which the pointers are bound. Indeed, the C99 standard revised the prototype of the function fopen() to the following:
/* new declaration of fopen() in <stdio.h>; */
FILE *fopen(const char * restrict filename,
const char * restrict mode);
Similar changes were applied to the entire standard C library: printf(), strcpy() and many other functions now take restrict pointers:
int printf(const char * restrict format, ...);
char *strcpy(char * restrict s1, const char * restrict s2);
C++ doesn't support restrict yet. However, since many C++ compilers are also C compilers, it's likely that this feature will be added to most C++ compilers too.
void f (const int* pci, int *pi ) // is *pci immutable?
{
(*pi)+=1; // not necessarily: n is incremented by 1
*pi = (*pci) + 2; // n is incremented by 2
}
int n;
f( &n, &n);
pci和pi指向的都是n,虽然pci被const修饰,但pci指向的内容却在函数中被改变了,当用restrict修饰符之后 void f ( const int * restrict pci , int * restrict pi ),问题解决了:一旦我们再有如:f ( &n , &n ) 的调用,编译器将给出错误提示,这是由于一个地址可以通过两个指针来访问。
If you specify type qualifiers such as void foo(int * restrict a);, the C compiler expresses it with array syntax void foo(int a[restrict]); which is essentially the same as declaring a restricted pointer.
但要注意:restrict是C99中新增的关键字,在C89和C++中都不支持,在gcc中可以通过—std=c99来得到对它的支持。