我已经回答了问题的答案@ What are the differences between const and volatile pointer in C? 我理解的解释是:
const修饰符意味着此代码不能更改变量的值,但这并不意味着无法通过此代码之外的方式更改该值。 但是,易失性说"这些数据可能会被其他人改变"因此编译器不会对该数据做出任何假设。
这意味着外部事件可以改变这两种类型的变量。
但是,那么const&的使用差异在哪里呢?易失性
在C中,编译器优化是否适用于const?
答案 0 :(得分:3)
volatile和const在很多方面都有所不同,它们是两个截然不同的特征。
将变量声明为const永远不会意味着“我希望在程序之外修改此变量”,我不确定从哪里得到这个想法。如果您希望在代码之外修改const变量,则必须将其声明为volatile const
,否则编译器可能会认为变量永远不会更改。
默认情况下,普通const变量就像任何类型的变量一样,它们根本无法被程序本身修改。
就像普通变量一样,const变量行为在很大程度上取决于声明它们的范围。大多数情况下,它们在文件范围内声明,然后它们表现为具有静态存储持续时间的其他变量,除非它们(可能)保存在内存的不同部分。如果它们在本地范围内声明,则它们可能会不时地更改它们所在的函数。
因此有很多情况可以优化const变量。一个常见的优化是“字符串池”,其中编译器检查相同的常量字符串文字是否在代码中出现两次,然后对它们使用相同的地址。如果您希望从外部源更改此类字符串,但未将它们声明为volatile,则会出现奇怪的错误。
对于volatile变量,它们可能会被外部源修改,但与const变量不同,它们也可能被程序修改。
答案 1 :(得分:1)
具有const
限定类型的对象是您可能在程序中声明的其他对象的对象,只是您无权修改它们。底层对象可能会更改,例如通过别名,编译器必须注意,如果此类事件可能已发生,则所有其他对象都必须注意。例如
void toto(double const* pi, double* x) {
printf("%g %g\n", *pi, *x);
printf("%g %g\n", *pi, *x);
*x = 5.0;
printf("%g %g\n", *pi, *x);
}
完全可以使用类似toto
的内容来调用toto(&a, &a)
,因此函数pi
和x
内部指向相同的内存。对于第二个printf
编译器可以假设,因为它没有在*pi
和*x
的值没有改变的平均时间内存储。但对于第三个printf
,它无法预见*pi
是否已更改,因此必须从内存重新加载该值。
volatile
与此不同。
void tutu(double volatile* pi, double* x) {
printf("%g %g\n", *pi, *x);
printf("%g %g\n", *pi, *x);
}
在这里,对于第二个printf
,编译器可以认为*x
没有改变,但对于*pi
,必须认为它可以必须必须从内存中重新加载它。 volatile
的用例在日常程序员生活中很少见,它们主要涉及对象
setjmp/longjmp
机制下答案 2 :(得分:0)
' const的'告诉编译器该值永远不会改变,不是由程序而是由其他人改变。当某些东西是const时,编译器会相应地优化代码,并且通常会用代码中的常量替换变量。因此,即使它在外面发生变化,程序也可能永远不会知道。
' volatile',相反告诉编译器变量可以随时从外部更改,然后编译器不会执行这样的优化,如将var放入寄存器,但总是如果它发生了变化,请从内存中读取它。
答案 3 :(得分:0)
演示const
的示例 function1()
{
int i = 10;
function2(&i);
}
function2(int const *ptr) // usage of const
{
*ptr = 20; //will cause error; outside function can't be modify the value of i
}
易失性的例子
function1()
{
while(1)
{
i = 20;
print(i);
}
}
function2()
{
i = 20;
while(1)
{
print(i);
}
}
考虑这两个功能。两者似乎都是一样的。 for optimization compiler将function1转换为function2。问题是如果i的值被另一个线程改变,那么两个函数变得不同,这里i的循环打印值和另一个模块改变i的值。所以我们永远不会得到i的值20。
volatile用于通知编译器不优化变量。
答案 4 :(得分:0)
const修饰符意味着此代码无法更改该值 变量,但这并不意味着该值不能被改变 意味着在此代码之外。
有两种不同的方法来应用const限定符。
程序不能修改const限定的对象,否则程序会有未定义的行为。一个const volatile
对象可以由OS /硬件/任何东西修改,但不能由程序分配。为避免疑义,const对象是定义使用const类型的对象。
指向const-qualified-type的指针防止(在编译时)通过该指针进行的修改,但是可以使用指向同一对象的其他指针来修改它。如果对象本身不是const,则定义行为。但是,编译器可能仍然假设只有程序修改了对象,从而考虑了操作系统/硬件/需要volatile
的任意修改。
指向非const限定类型的指针与指向const的指针完全相同,只要通过其他指针进行修改即可。
然而,volatile表示"此数据可能会被此程序中的代码以外的其他内容更改"因此编译器在优化时不会对该数据做出任何假设。
所以区别在于:
#include <stdio.h>
void some_other_function(const int *);
int main() {
int a = 0;
int volatile b = 0;
int const c = 0;
int const *constptr = &a;
int *ptr = (int*) constptr;
printf("%d\n", a); // compiler can assume a == 0 at this point, and
// replace the code with puts("0") if it wants to
printf("%d\n", b); // compiler cannot assume a value for b, it's volatile[*]
some_other_function(constptr); // defined in another TU
printf("%d\n", a); // compiler can *no longer* assume that a == 0,
// it might have changed
*ptr = 1; // there's another example of a changing, legally
some_other_function(&c);
printf("%d\n", c); // compiler can assume c == 0 because c is const
}
[*]虽然我说&#34;不能假设一个值&#34;但可能是某些假设的C实现碰巧知道没有操作系统或硬件机制来修改自动变量以任何方式需要volatile
来检测。特别是在这种情况下,没有对b
的引用已逃脱该功能。如果是这样,那么您可能会发现实现实际上可以忽略此特定代码中的volatile
,但它可能会处理外部全局volatile
变量&#34;正确&#34;因为它知道链接器提供了将它们映射到I / O端口或其他地址的方法。
答案 5 :(得分:0)
在下面的情况下,可以很容易地看到Volatile和Const之间的差异,
1)如果您将某个变量称为Const,则可能无法通过您的程序进行修改。
2)如果你说volatile,它只是提示编译器不要优化代码,因为值可能会从外部线程或其他程序改变。
3)如果我们将变量定义为Const Volatile,这意味着该变量不能被同一个程序修改,不会被编译器优化,可以被外部线程或程序修改。
示例:
如果我写下面的函数,
const freq = 10;
calfreq()
{
return (Const freq * 2);
}
在这种情况下,编译器可以优化代码
return(20);
。
但是在这种情况下,由于外部硬件/线程/程序,freq值可能会发生变化 所以,如果我说Const Volatile,那么问题就会得到解决。