如果汇编指令修改了内存,但是GCC本身不知道,因为在输出部分中没有描述,则需要在修改描述部分中添加“内存”以告知GCC内存已被修改, GCC知道了这些信息之后,将在该部分指令之前插入必要的指令,并且针对缓存优化的寄存器中的变量值将首先写回到内存中,如果您想使用这些变量以后,再读一遍.
使用“ volatile”也可以达到这个目的,但是我们在每个变量之前添加此关键字,最好使用“ memory”.
关于编译器优化的两种限定词: volatile和strict
++ / cppjs / 2008331 / 107755.html
我最近开始学习C语言. 我想记录一下我在学习过程中的经验. 让我将其作为我学习经历的笔记. 如果您不小心阅读了这些文章,则可以帮助我指出一些未正确理解的文章. 在这里,我将非常感谢您. 哈哈.
使用两种限定符(volatile和strict)与编译器的优化有一定关系. 在变量类型定义中使用关键字volatile指示该变量的值中存在不确定因素. 也就是说,此变量不仅会被我们编写的程序更改,还可能会被外部代理程序更改(例如: 硬件中断,外部程序等). 这样,不能保证如果程序不更改该变量的值并且有多次调用,则在寄存器中输入的值将是正确的.
从编译器优化的角度,举一个例子:
int x = 5;
int a,b;
a = x;
b = x;
因为程序不会更改X的值,但是有很多调用,编译器将为a分配一个值以优化运行速度,并将X的值从内存中放入寄存器中. 当给b赋值时,不必再次读取X存储器地址中的值,而是直接将5赋给寄存器中的b. 此优化对于普通变量没有问题. 但是,如果将其定义为volatile int x;这意味着x可以由程序代码之外的其他代理更改. 如果编译器也使用此优化,则很可能在分配了b的值后,x的值已被程序外部的硬件中断更改了. 这样,从寄存器获得的值肯定是错误的.
因此,当将volatile关键字添加到变量中时,除了表明该变量可以被其他代理更改外,它还明确指出编译器无法以上述方式优化此变量: 每次调用此变量时,从变量的地址而不是寄存器中获取值(此变量使用的硬件内存地址用于与并行运行的其他程序共享数据,因此,程序本身更改变量值还是其他代理更改变量值,是要更改内存地址数据. )
看一个有趣的例子:
int方(volatile int * a)
{
return(* a * * a);
}
该函数的目的是计算平方根,但是由于指针使用volatile关键字,因此不能保证两次获得的指针地址中的值都相同,因此计算结果可能不是我们需要. 考虑更改为:
int方(volatile int * a)
{

int temp = * a;
return(temp * temp);
}
restrict关键字只能用于修改指针,指示定义的指针是访问指针中数据的唯一方法. 目的是告诉编译器可以进行一些优化. 查看示例:
int x = 2;
int * a =(int *)malloc(sizeof(int));
* a = 2;
int * b =&x;
* a + = 2;
* b + = 2;
x * = 3;
* a + = 3;
* b + = 3;
在编译器进行优化时,可以使用以下语句代替: * a + = 5;这对于a是正确的,但是如果您使用* b + = 5来优化b,那是不正确的. 因为其他变量会影响结果. 因此,当编译器不确定某些因素时,它将放弃寻找优化的方法. 如果在变量前添加strict关键字. 它告诉编译器可以放心地对其进行优化. 但是,编译器不会验证您定义为strict的指针是否确实是访问某些数据的唯一方法;它会导致错误. 就像数组的下标超出范围一样,如果您不遵守规则,则编译器不会指出错误,但后果是您自己负责的: )
还要看一个有趣的类别:
voidchange_array(restrict int * array,const limit int * value,const int size)
{
for(int i = 0; i {
array [i] + = * value;
}
}
int main(void)
{
int * array [SIZE] = {1,2,3};
change_array(array,&array [0],SIZE);
for(int i = 0; i {
printf(“%d \ n”,array [i]);
}
}
如果编译器支持优化,则运行后的结果为: 2 3 4而不是实际的正确结果: 2 4 5.这表明在定义函数时两个指针受到限制,因此编译器对其进行了优化: 当程序调用该函数时,将在寄存器中生成值指针的变量值的副本. 随后的执行是获取寄存器的值. 同时,可以看出,当您不遵循由strict定义的指针定义的规则并且只能由指针修改(函数中值指针所指向的数据时,数组指针也是在调用main时进行了修改),编译器不会进行检查.
为了进行优化,必须强制使用volatile,并建议使用strict. 也就是说,添加volatile不会强制优化,而添加strict编译器可能不一定会优化. 在大多数情况下,限制的结果与不添加任何内容的结果相同. Restrict仅告诉编译器可以自由进行一些优化假设. 同时,它还告诉调用方仅使用符合限制中定义的条件的参数,如果您不遵守,则呵呵. .
关键字strict是由C99标准添加的,在C ++中不受支持,因此我无法通过在VC ++中添加restrict关键字来进行编译: (
关于加入限制,我还在互联网上找到了一个简短的故事:
为了提高Cray机器的效率,ANSI C委员会提出了一种名为noalias的机制来解决此问题. 它被用来解释C指针可以被视为没有别名,但是这种机制还不成熟. 此事件激怒了Dennis Ritchie,他只是干预了C的标准化过程. 他写了一封公开信,说“ noalias必须侧身站立,这是不能商量的. ”
后来,Cray的Mike Holly发现了这个问题,并向数值C语言扩展工作组和C ++委员会提出了改进的抗锯齿建议. 建议的想法是允许程序员通过采用指针作为限制来声明可以将其视为别名. 该提议已被C99接受,但标准的C ++拒绝了.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-275394-2.html
新生代最具商业价值的红烧肉
要是自己不努力