参考自restrict

restrict解释

restrict关键字出现于C99标准,wiki上的解释restrict from wiki

In the C programming language, as of the C99 standard, restrict is a keyword that can be used in pointer declarations. The restrict keyword is a declaration of intent given by the programmer to the compiler. It says that for the lifetime of the pointer, only the pointer itself or a value directly derived from it (such as pointer + 1) will be used to access the object to which it points. This limits the effects of pointer aliasing, aiding optimizations. If the declaration of intent is not followed and the object is accessed by an independent pointer, this will result in undefined behavior. The use of the restrict keyword in C, in principle, allows non-obtuse C to achieve the same performance as the same program written in Fortran.[1]

在C编程语言中,从C99标准开始,restrict是一个可以在指针声明中使用的关键字。restrict关键字是由程序员给编译器的一种意向声明。它表示在指针的生命周期内,只有指针本身或直接从指针派生的值(如指针+ 1)将用于访问指针指向的对象。这限制了指针别名的效果,有助于优化。如果没遵循指针声明的意图,使用不受约束的指针对其指向对象存取,将导致结果是未定义的。

实例

上面这堆翻译好像我只看懂了:restrict关键字用于指针的声明。那到底什么意思呢?在进一步了解restrict之前,需要了解什么是pointer aliasing

pointer aliasing是指多个指针指向同一块内存区域,例如:

int a = 10;
int* ptr1 = &a;
int* ptr2 = &a;

则ptr1、ptr2互称对方为自己的pointer aliasing。考虑下面这个函数:

int foo(int* a, int* b)
{
*a = 2;
*b = 3;
return *a + *b;
}

一般情况下,编译器翻译出来的汇编代码会类似(以ARM汇编为例):

01    str     r0, [fp, #-8]			@传递参数指针a
02 str r1, [fp, #-12] @传递参数指针b
03 ldr r3, [fp, #-8] @得到指针a
04 mov r2, #2
05 str r2, [r3] @*a = 2;
06 ldr r3, [fp, #-12] @得到指针b
07 mov r2, #3
08 str r2, [r3] @*b = 3;
09 ldr r3, [fp, #-8] @得到指针a
10 ldr r2, [r3] @r2 = *a, 重读*a,因为如果a==b,则08行会覆盖05行的赋值!!!!!
11 ldr r3, [fp, #-12] @得到指针b
12 ldr r3, [r3] @r3 = *b;
13 add r0, r2, r3 @*a + *b;

如果我们可以提前告诉编译器a != b,则编译器可以优化出更简洁的汇编(假设a、b指针都是非volatile的):

01    str     r0, [fp, #-8]			@传递参数指针a
02 str r1, [fp, #-12] @传递参数指针b
03 ldr r3, [fp, #-8] @得到指针a
04 mov r2, #2
05 str r2, [r3] @*a = 2;
06 ldr r3, [fp, #-12] @得到指针b
07 mov r1, #3
08 str r1, [r3] @*b = 3;
09 add r0, r1, r2 @*a + *b;

比上面少了4条指令。为什么呢?因为上面那段汇编中得考虑一种情况,如果指针a == b,那么第08行的指针赋值会覆盖05行的指针赋值,为了保险起见,*a + *b就得重新从内存中取值,才能得到正确的结果。如果我们显式的告诉编译器a != b,则编译器就会使用寄存器里面的缓存数据来优化代码。如何显式告诉编译器呢?就是用restrict关键字来修饰指针。

注意事项

但是有点需要注意,不是说用restrict修饰指针后就保证了指针不会出现pointer aliasing,这种保证由程序员自己编码时确保。就是说程序员自己保证对同一内存区域的引用只有一个指针指向,然后通过restrict修饰此指针变量,在开启编译优化后,编译器将会特别留意被restrict修饰的指针,进行优化。

restrict关键字只能修饰object类型的指针(例如int restrict *pfloat (* restrict foo)(void)都是错误的用法)。restrict仅用于修饰左值(lvalue)。例如使用它强制转换指针或者修饰函数返回值都是错误的用法。

解释下2个名词:

object:

在C语言中,对象是执行环境中的数据存储区域,其内容可以表示值(当解释为具有特定类型时,值是对象内容的含义)。每个对象有如下特征:

  • 尺寸(能用sizeof计算)
  • 有对齐需求
  • 存储期(automatic, static, allocated, thread-local)
  • 有效类型
  • 值(可能是不确定的)
  • 可选地,表示此对象的标识符(就是变量名)

int restrict *p 修饰的不是指针。

float (* restrict foo)(void),foo指针指向的区域明显不具备存储数据的能力,*foo = 12是非法的,因为如果它是一个函数指针,指向的内存区域是只读的。

左值(lvalue):

只能出现在C语言赋值表达式左边的。

显然ret = fun()、a = (int)b就说明了函数返回值,强转都是属于右值。

c99标准的restrict关键字的更多相关文章

  1. restrict关键字(暗示编译器,某个指针指向的空间,只能从该指针访问)

    我们希望某个对象(内存空间)不被修改的通常做法是什么?声明该空间的const类型,但是这样真的可以吗?是不是的,由于const空间对象的指针是可以付给一个非const值指针的.所以这仍然无法不让该空间 ...

  2. C89 和 C99 标准比较

    注1: GCC支持C99, 通过 --std=c99 命令行参数开启,如: 代码:gcc --std=c99 test.c    注2:FFMPEG使用的是C99.而VC支持的是C89(不支持C99) ...

  3. restrict关键字

    值得注意的是,一旦你决定使用restrict来修饰指针,你必须得保证它们之间不会互相重叠,编译器不会替你检查. 关键字restrict有两个读者.一个是编译器,它告诉编译器可以自由地做一些有关优化的假 ...

  4. Visual Studio2013的C语言编译器对C99标准的支持情况

    Visual Studio2013终于开始比较良好地支持C99特性了.在此之前,如果用C语言写代码的话,变量名都需要放到函数体的前面部分,代码写起来十分别扭. 而Visual Studio2013中的 ...

  5. C89标准和C99标准C11标准的区别

    转载 C89标准和C99标准C11标准的区别 C99对C89的改变 1.增加restrict指针 C99中增加了公适用于指针的restrict类型修饰符,它是初始访问指针所指对象的惟一途径,因此只有借 ...

  6. [转] restrict关键字用法

    PS: 在函数中,指针参数指定了restrict,表示这个指针指向的这段区域只能通过这个指针修改 c99中新增加了一个类型定义,就是restrict. 看了下网上的相关贴子,但还是问题解决的不够.下面 ...

  7. C 语言restrict 关键字的概念及使用例子

    restrict是c99标准引入的,它只可以用于限定和约束指针,并表明指针是访问一个数据对象的唯一且初始的方式.即它告诉编译器,所有修改该指针所指向内存中内容的操作都必须通过该指针来修改,而不能通过其 ...

  8. [转]Restrict关键字

    0 定义 C99中新增加的用于修饰指针的关键字,用于表示该指针所指向的内存,只有通过该指针访问得到(如下ptr指向的内存单元只能通过ptr访问得到).从而可以让编译器对代码进行优化,生成更有效率的汇编 ...

  9. C99标准新特性的说明

    C99标准新特性的说明   一.说明 ====== 这里的讨论的是C语言的国际标准,即国际标准化组织ISO,制定的C语言标准.历史上ISO制定过4个版本的C语言标准,他们分别是:C90(ISO/IEC ...

随机推荐

  1. 核密度估计 Kernel Density Estimation (KDE) MATLAB

    对于已经得到的样本集,核密度估计是一种可以求得样本的分布的概率密度函数的方法: 通过选取核函数和合适的带宽,可以得到样本的distribution probability,在这里核函数选取标准正态分布 ...

  2. Activemq首次运行报错 “找不到或无法加载主类”

    首次运行Program Files\apache-activemq-5.10.0\bin目录下的activemq.bat文件,报错信息如下: 找不到或无法加载主类 Files\apache-activ ...

  3. JVM内存模型(转载)

    原文地址:http://blog.csdn.net/u012152619/article/details/46968883 JVM定义了若干个程序执行期间使用的数据区域.这个区域里的一些数据在JVM启 ...

  4. 20155232 2016-2017-2 《Java程序设计》第2周学习总结

    20155232 2016-2017-2 <Java程序设计>第2周学习总结 教材学习内容总结 类型 基本类型 整数(short.int.long) 字节(byte) -128~127 字 ...

  5. 20155322 2016-2017-2 《Java程序设计》第4周学习总结

    20155322 2016-2017-2 <Java程序设计>第4周学习总结 教材学习内容总结 本周的学习内容为课本第六章与第七章: 第六章主要讲继承和多态.首先是我们为什么要学习继承和多 ...

  6. 20145234黄斐《java程序设计》第二周

    教材学习内容总结 类型 Java可区分为基本类型(Primitive Type)和类类型(Class Type),其中类类型也叫参考类型(Reference Type). 字节类型,也叫byte类型, ...

  7. zabbix最新版3.4搭建(根据官方文档适当修改)

    操作系统:CentOS Linux release 7.4.1708 (Core) 1.安装apache 1.1 安装apache yum install httpd httpd-devel 1.2 ...

  8. day4 边缘检测Canny

    1.canny边缘检测 # coding=utf-8 import cv2 import numpy as np filename = 'woman.JPEG' #读入图像,以灰度格式 img = c ...

  9. [转]理解Linux文件系统之inode

    很少转发别人的文章,但是这篇写的太好了. 理解inode   作者: 阮一峰 inode是一个重要概念,是理解Unix/Linux文件系统和硬盘储存的基础. 我觉得,理解inode,不仅有助于提高系统 ...

  10. WPF DataGridTable

    由于项目要显示表头合并,而数据源列随时变更,又不想重复的画表格,就实现动态数据(dynamic)绑定和配置数据列模板的方式 编辑DataGridColumnHeader样式实现表头合并:效果如下 实现 ...