- 編寫高質量代碼:改善C程序代碼的125個建議
- 馬偉 著
- 1382字
- 2019-01-01 01:33:15
建議11:盡量使用const聲明值不會改變的變量
從字面上理解,const是constant的縮寫,是恒定不變的意思,也翻譯為常量、常數等。正是因為這一點,看到const關鍵字,很多人就認為被const修飾的值是常量。其實,在C語言中,關鍵字const的功能非常強大,它不僅可以用來修飾普通變量、數組變量與指針變量等,還可以用來修飾函數的參數、返回值與函數本身。這些將會在后面的章節逐一詳細講解,本節只討論使用const來修飾變量的情況。
對變量來說,const關鍵字可以限定一個變量的值不允許被改變,從而保護被修飾的東西,防止意外修改發生,這在一定程度上可以提高程序的安全性和可靠性。但是要正確地使用const變量,我們必須弄清以下幾點。
1.const變量是只讀變量,不是常量
提到const變量,總有人喜歡把它和常量混為一談。其實const變量不是常量,準確地說它應該是只讀的變量。為了讓大家更好地區分這兩個概念,我們來看下面的例子:
const int array_num=10; int arr[array_num]={1,2,3,4,5,6,7,8,9};
在標準的ANSI C中,上面的這種寫法是錯誤的,因為數組的大小應該是個常量,而const int array_num只是一個只讀變量。雖然常量也是只讀的、不可修改的(例如10、‘C’等),但只讀變量卻不等于常量,只讀變量被編譯器限定為不能夠被修改。
實際上,根據編譯過程及內存分配來看,這種用法本來應該是合理的,只是ANSI C對數組的規定限制了它。而在C++中,上面的這種寫法確實是正確的。
2.確保變量的值不被修改
可以說,const關鍵字的最大作用就是確保變量賦初值之后,其值不會被任何程序修改。如下面的示例代碼所示:
const int array_num=10; array_num++; // 錯誤,不可以被修改
很顯然,語句“array_num++”是錯誤的。同樣,對于外部變量,const一樣可以確保其變量的值不被修改,如下面的代碼所示:
extern const int i; // 正確的引用 extern const int i="10"; // 錯誤,不可以被再次賦值
盡管如此,網上仍然流傳著一種修改const變量的說法,如代碼清單1-30所示。
代碼清單1-30 const變量使用示例
#include <stdio.h> int main(void) { const int i1=10; int *p1=(int *)&i1; int *p2=p1; *p1=100; printf("%d %d %d\n",i1,*p1,*p2); printf("%p %p %p\n\n",&i1,p1,p2); return 0; }
有人說,這樣const變量就能被修改了,但運行上面的程序,const變量的值根本沒有改變,代碼清單1-30的運行結果如圖1-45所示。

圖1-45 代碼清單1-30的運行結果
在圖1-45中,雖然“i1,*p1,*p2”所得的值不同,但“&i1,p1,p2”卻是同一個地址,既然是同一地址,為什么輸出不一樣的值?
為了進一步查看其原因,我們在代碼清單1-30中添加如下一條語句:
printf("%d\n",*((int *)0x0012FF74));
這樣就可以直接輸出地址所存的值了。得到的結果在我們的預料之中,為“100”。或許大家認為這樣就改變了const變量的值。
其實,“int*p1=(int*)&i1;”表面上給了它們相同的指針,但是const變量的值是保存在數據段(只讀)的,通過地址0x0012FF74查內存文件可得知其屬于堆棧段。也就是說,雖然地址相同,但const變量讀取的是數據段,而通過指針讀取到的是堆棧段。
由此可見,const提供了一種保護機制,能在編譯階段阻止其變量的值被修改。但它并不能完全防止在程序的內部(甚至是外部)來修改這個值。也就是說,const變量是只讀變量,既然是變量,那么就可以獲取其地址,然后修改其值。因此,當匯編成二進制之后,這種保護機制就不復存在了。
3.節省空間,避免不必要的內存分配
使用const變量除了可以確保變量值不被修改之外,同時它還可以節省存儲空間,避免不必要的內存分配。通常,編譯器并不為普通const只讀變量分配存儲空間,而是將它們保存在符號表中,這使得它成為一個編譯期間的值,沒有了存儲與讀內存的操作,從而提高效率。
- Mastering Entity Framework Core 2.0
- AngularJS Testing Cookbook
- Offer來了:Java面試核心知識點精講(原理篇)
- Python完全自學教程
- Getting Started with Laravel 4
- Python算法指南:程序員經典算法分析與實現
- 搞定J2EE:Struts+Spring+Hibernate整合詳解與典型案例
- Windows Embedded CE 6.0程序設計實戰
- Learning Node.js for .NET Developers
- 百萬在線:大型游戲服務端開發
- Manage Your SAP Projects with SAP Activate
- 計算機常用算法與程序設計教程(第2版)
- Unity虛擬現實開發圣典
- Puppet Cookbook(Third Edition)
- Learning Java Lambdas