日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

【软件开发底层知识修炼】二十八 C/C++中volatile的作用

發布時間:2023/12/10 c/c++ 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【软件开发底层知识修炼】二十八 C/C++中volatile的作用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • 上一篇文章學習了C/C++中的指針與數組的區別,點擊鏈接進行查看:【軟件開發底層知識修煉】二十七 C/C++中的指針與數組是不同的
  • 本篇文章將學習volatile關鍵字在C/C++中的作用

文章目錄

  • 1 實例代碼分析
  • 2 問題分析
  • 3 解決方案
  • 4 拓展: const和volatile
  • 4 總結

1 實例代碼分析

在講解volatile關鍵字的作用之前,我們先來看一個代碼的例子,代碼如下:

  • main.c
#include <stdio.h> #include <pthread.h>extern const int g_ready;int main() {launch_device();while( g_ready == 0 ){sleep(1);printf("main() : g_ready = %d\n", g_ready);}printf("main() : g_ready = %d\n", g_ready);return 0; }
  • device.c
#include <stdio.h> #include <pthread.h> #include <unistd.h>int g_ready = 0;void* th_fn(void* args) {sleep(5);g_ready = 1;printf("th_fn() : g_ready = %d\n", g_ready); }void launch_device() {pthread_t tid = 0;pthread_create(&tid, NULL, th_fn, NULL); }

上面的代碼,是非常容易懂的,這里就不再多說。我們直接編譯運行看看:

  • gcc -pthread main.c device.c -o test.out
  • ./test.out

運行結果如下:

這個結果對于我們來說其實挺容易懂的。就是main中的while循環先每隔一秒打印執行一次,然后5秒后th_fn函數開始執行,th_fn函數將g_ready變量變為1,然后打印一個語句。最后回到main中的while循環,由于while中上次最后一秒現在才執行完,打印一句,然后由于此時g_ready為1,所以退出循環,然后打印循環外的一個語句,然后結束程序的運行。這種結果,其實是比較容易理解的。也是比較普遍的結果。

但是如果我們再編譯上述代碼的時候,加上了-O3選項,該選項是優化選項,且級別比較高。編譯運行結果如下:

  • gcc -O3 -pthread main.c device.c -o test.out
  • ./test.out

運行結果如下動態圖:

由以上結果我們可以看到,程序陷入了死循環,g_ready沒有被改變一直都是0,所以main中的while循環一直在執行。對于這個結果,可能并不是所有人都知道為什么。下面,我們就要來講解為什么會產生上面的運行結果。

2 問題分析

-O3選項是讓編譯器對代碼進行優化。

  • 編譯優化時,編譯器根據當前文件進行優化。
  • 為了效率上的提高,優化時編譯器將變量值從內存中讀取進入寄存器
  • 每次要訪問變量時直接從寄存器讀取。畢竟寄存器的存取比內存的存取快很多。

那么,我們明白了優化對變量的影響。對于上述的代碼,如果在編譯時加了-O3選項。編譯優化時,編譯器會將變量g_ready的值放到寄存器中,以后每次使用該變量就從寄存器中取出g_ready的值使用即可。這樣雖然是速度快了,但是當在th_fn函數中改變了g_ready的值后,在內存中確實g_ready的值已經變為1了,但是在剛剛那個寄存器中,最開始將g_ready的值也就是0存進去的,一直都沒有改變過,但是呢,由于編譯器的優化,每次在使用g_ready的變量的時候,都是從寄存器中直接取出值來使用…

說到這里,應該都能夠明白了,此時從寄存器中取出的值就一直都是0.然后while一直循環。

3 解決方案

編譯的時候使用-O3選項是很常用的。那么如何才能既使用這個-O3選項,又使得上述程序按照我們的意愿來執行呢?volatile就此出場。

使用volatile關鍵字修飾可能被意外修改的變量(內存),從而禁止編譯器對該變量進行優化。

  • volatile一般修飾的是一種易變的變量
  • volatile可理解為一種編譯器警告指示字,它告訴編譯器必須每次都直接去內存中取變量值。

那么在上述的代碼中,我們將main.c中的extern const int g_ready; 改為:extern volatile const int g_ready; 再重新進行優化的編譯,然后運行,結果就是正確的運行。可以自己嘗試做實驗!

4 拓展: const和volatile

細心的朋友會發現,在main.c程序中,我們改完后,成這樣了:extern volatile const int g_ready; 又是const又是volatile的。我們上面說過,volatile修飾的是意變的變量,而const修飾的變量是不能被修改的,有的人叫它常量,不可變的。而實際上在編程語言中的解釋是這樣的:const修飾的變量在當前文件中不能夠出現在賦值符號的左邊。 所以我們可以看到,在main.c這個文件中g_ready這個變量,并沒有出現在賦值符號的左邊,所以是沒有問題。但是在device.c文件中g_ready是沒有被const修飾的,它就可以出現在賦值符號的左邊,可以被改變。這樣一來,在device.c中修改g_ready這個變量,在main.c中的g_ready也間接被改變了。所以,我覺得說const修飾的是常量這個說法不夠準確,說它是變量但是不能夠出現在賦值符號的左邊更加準確。

下面就總結一下const和volatile關鍵字:

  • const表示修飾的變量在當前文件中不能出現在賦值符號的左邊,不能直接被改變,但是可以間接被改變
  • volatile表示修飾的變量每次使用的時候直接從內存中讀取
  • const和volatile同時修飾變量時互不影響。

4 總結

  • 編譯優化時,編譯器僅根據當前文件進行優化
  • 編譯器的優化策略可能造成一些意外
  • volatile強制編譯器必須從內存中取變量值
  • const和volatile同時修改變量時,互相不影響彼此的含義。

總結

以上是生活随笔為你收集整理的【软件开发底层知识修炼】二十八 C/C++中volatile的作用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。