簡體   English   中英

C中const和volatile限定詞之間的用法明智區別?

[英]Usage wise difference between const & volatile qualifier in C?

我已經經歷了問題的答案@ C中的const和volatile指針有什么區別? 我了解以下解釋:

const修飾符表示此代碼無法更改變量的值,但這並不意味着該值不能通過此代碼外部的方式進行更改。 但是,volatile說“此數據可能會被其他人更改”,因此編譯器將不對該數據做任何假設。

這意味着兩種類型的變量都可以通過外部事件進行更改。

但是,那么const和volatile在用法上的區別在哪里?

在C語言中,編譯器優化對const是否有效?

volatile和const在許多方面都不同,它們是兩個截然不同的功能。

像聲明const一樣聲明變量絕不會意味着“我希望在程序外部修改此變量”,但我不確定您從何處得到了這個想法。 如果您希望在代碼外修改const變量,則必須將其聲明為volatile const否則編譯器可能會認為該變量從未更改。

默認情況下,普通const變量就像任何類型的變量一樣,它們根本無法被程序本身修改。

就像普通變量一樣,const變量的行為在很大程度上取決於聲明它們的范圍。 通常,它們在文件作用域中聲明,然后與具有靜態存儲持續時間的其他變量一樣起作用,除非它們(可能)保存在內存的不同部分。 如果在本地范圍內聲明它們,則在調用它們所駐留的函數時可能會不時更改。

因此,在很多情況下可以優化const變量。 一種常見的優化是“字符串池”,其中編譯器檢查相同的常量字符串文字是否在代碼中出現兩次,然后為它們使用相同的地址。 如果您希望從外部來源更改這些字符串,但沒有將它們聲明為易失性,則會收到奇怪的錯誤。

至於volatile變量,它們可以由外部源進行修改,但與const變量不同,它們也可以由程序進行修改。

具有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(&a, &a)類的東西調用toto是完全可以toto(&a, &a)因此在函數pix指向相同的內存。 對於第二個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機制下
  • 或通過其他線程

'const'告訴編譯器該值是永遠不會更改的,而不是由程序或其他任何人都不會更改。 當某些內容為const時,編譯器將相應地優化代碼,通常會將變量替換為代碼中的常量。 因此,即使外部更改,該程序也可能永遠不會知道。

相反,“易失性”告訴編譯器該變量可以隨時從外部更改,然后編譯器將不會執行優化操作(例如將var放入寄存器中),但始終會從內存中讀取該變量(以防萬一)改變。

演示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);
       }
 }

考慮這兩個功能。 兩者似乎都是一樣的。 為了進行優化,編譯器將function1轉換為function2。 問題是,如果i的值被另一個線程更改,則兩個函數會變得不同,此時,循環打印i和另一個模塊的值會更改i的值。 因此我們永遠不會得到i的值20。

volatile用於通知編譯器不要優化變量。

const修飾符表示此代碼無法更改變量的值,但這並不意味着該值不能通過此代碼外部的方式進行更改。

應用const限定符有兩種不同的方法。

程序不能修改const限定對象 ,否則該程序具有未定義的行為。 const volatile對象可以由OS /硬件/任何對象修改,但不能由程序分配。 為避免疑問,const對象是其定義使用const類型的對象。

指向const限定類型的指針可防止(在編譯時)通過該指針進行修改,但是指向同一對象的其他指針也可用於修改它。 如果對象本身不是const,則定義行為。 但是,編譯器仍然可以假設只有程序才能修改對象,考慮到OS /硬件/需要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
}

[*]盡管我說它“不能假設一個值”,但可能是某些假設的C實現恰巧知道沒有OS或硬件機制通過任何需要volatile檢測的方式來修改自動變量。 特別是在這種情況下,對b引用都沒有轉義該函數。 如果是這樣,那么您可能會發現該實現實際上可以忽略此特定代碼中的volatile ,但是也許它“適當地”對待外部全局volatile變量,因為它知道鏈接器提供了一種將它們映射到I / O端口地址的方法。管他呢。

在波紋管情況下,可以很容易地看出Volatile和Const之間的區別,

1)如果您將某個變量稱為Const,則可能無法通過程序進行修改。

2)如果您說的是volatile,它只是提示編譯器不要優化代碼,因為該值可能會從外部線程或其他程序中更改。

3)如果我們將變量定義為Const Volatile,則意味着該變量不能由同一程序修改,不能由編譯器優化,也可以由外部線程或程序修改。

例:

如果我寫下面的函數,

const freq = 10;
calfreq()
{
return (Const freq * 2);
}

在這種情況下,編譯器可以優化代碼以

return(20);

每時每刻。

但是在我的情況下,由於外部硬件/線程/程序的緣故,頻率值可能會發生變化。因此,如果我說的是Const Volatile,那么問題將得到解決。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM