您好,登錄后才能下訂單哦!
你能很隨意地說出C語言中 auto,register,volatile,extern,static,const這幾個關鍵字的含義和用法么?
auto
這個關鍵字用于聲明變量的生存期為自動。
C程序是面向過程的,在C代碼中會出現(xiàn)大量的函數(shù)模塊,每個函數(shù)都有其生命周期(也稱作用域),在函數(shù)生命周期中聲明的變量通常叫做局部變量,也叫自動變量。
auto 變量是用堆棧(stack)方式占用儲存器空間,因此,當執(zhí)行此區(qū)段是,系統(tǒng)會立即為這個變量分配存儲器空間,而程序執(zhí)行完后,這個堆棧立即被系統(tǒng)收回.在大括號{}內聲明.這個關鍵字不怎么多寫,因為所有的變量默認就是auto的。
例子
#include <stdio.h> void sayHi(); int main() { printf("Hello!\n"); sayHi(); return 1; } void sayHi() { //int age = 20; auto age = 20; printf("I'm %d.\n",age); }
register
這個關鍵字命令編譯器盡可能的將變量存在CPU內部寄存器中而不是通過內存尋址訪問以提高效率.但也只是盡可能,因為cpu就那幾個寄存器,不能全給你用了。
限制:必須是能被cpu寄存器所能接受的類型,必須為單個的值,并且長度應小于或者等于整型的長度,而且registor變量可能不存放在內存中,所以不能用取地址運算符來獲取地址。
例子:(算Pi)
#include <stdio.h> #include "stdlib.h" #include <time.h> #include <sys/time.h> #define SCALE 10000 #define ARRINIT 2000 //int pow(int num, int n); int main() { struct timeval tpstart,tpend; int timeuse; gettimeofday(&tpstart,NULL); pi_digits(100000); gettimeofday(&tpend,NULL); timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec; printf("\nDone in %d ms.\n",timeuse); return 1; } void pi_digits(int digits) { int carry = 0; int arr[digits + 1]; int i,j; for (i = 0; i <= digits; ++i) arr[i] = ARRINIT; for (i = digits; i > 0; i-= 14) { //int sum = 0; register int sum = 0; for (j = i; j > 0; --j) { sum = sum * j + SCALE * arr[j]; arr[j] = sum % (j * 2 - 1); sum /= j * 2 - 1; } printf("%04d", carry + sum / SCALE); carry = sum % SCALE; } }
將pi_digits函數(shù)中的sum聲明為register之后,運行結果:
運行時間有明顯的減少。
volatile
在本次線程內, 當讀取一個變量時,為提高存取速度,編譯器優(yōu)化時有時會先把變量讀取到一個寄存器中;以后,再取變量值時,就直接從寄存器中取值;當變量值在本線程里改變時,會同時把變量的新值copy到該寄存器中,以便保持一致。
當變量在因別的線程等而改變了值,該寄存器的值不會相應改變,從而造成應用程序讀取的值和實際的變量值不一致。
當該寄存器在因別的線程等而改變了值,原變量的值不會改變,從而造成應用程序讀取的值和實際的變量值不一致。
volatile應該解釋為“直接存取原始內存地址”比較合適,“易變的”這種解釋簡直有點誤導人。
這個在多線程編程中常常會用到。
深究的話可以扯到編譯原理里面去了。
例子:
#include <stdio.h> int main() { //Has bug when not using volatile //int result = 0; volatile int result = 0; int a = result; printf("result = %d\n",a); int input = 1; __asm__ __volatile__ ("addl %2,%0":"=r"(result):"r"(result),"r"(input)); int c = result; printf("result = %d\n",c); return 1; }
使用匯編的目的是騙過編譯器改變寄存器中變量的值。
在沒有使用volitile的情況下:
第一個用的是-g參數(shù),沒有使用編譯器的優(yōu)化,所以結果是正確的。
第二個使用的是-O2參數(shù),等于是編譯release版本,gcc對代碼進行了優(yōu)化,比如常量傳播,再次運行,結果并不正確。
接下來使用volitile關鍵字,結果正確。
尼瑪,匯編是硬傷。
注意:頻繁地使用volatile很可能會增加代碼尺寸和降低性能,因此要合理的使用volatile。
extern
意為“外來的”···它的作用在于告訴編譯器:有這個變量,它可能不存在當前的文件中,但它肯定要存在于工程中的某一個源文件中。
最常用的狀態(tài)是多個文件的工程的時候,調用另外文件的共有變量和函數(shù)。
例子:
a.c
#include <stdio.h> int a = 20; int fun(int n) { int sum = 0; while(n>1) { sum += n--; } return sum; }
#include <stdio.h> extern int a; extern int fun(int n); int main() { printf("fun: %d\n",fun(a)); return 1; }
static
c語言中的static和extern是相對的。
static也可以用來休息變量和函數(shù)。
在修飾變量的時候,可以是:
全局變量,作用域僅限于變量被定義的文件中,其他文件即使使用extern聲明也沒辦法使用他。
局部變量,只能在函數(shù)中使用,同一個文檔中的其他函數(shù)也用不了。由于static修飾的變量存放在內存的靜態(tài)區(qū),所以即使這個函數(shù)運行結束,這個靜態(tài)變量的值也不會銷毀,下次仍然使用內存中的這個值。
在修飾函數(shù)的時候,
函數(shù)的作用域僅局限于本文件,也就是內部函數(shù),好處:不同的人編寫不同的函數(shù)時,不用擔心自己定義的函數(shù)是否會與其他文件中的函數(shù)重名。
例子:函數(shù)使用計數(shù)器
#include <stdio.h> void count(); int main() { int i; for (i = 1; i <= 3; i++) count(); return 0; } void count() { static num = 0; num++; printf("I have been called %d times.\n",num); }
const
const稱之為常量修飾符,即就是說其所修飾的對象為常量。當你代碼中想要設法阻止一個變量被改變,那么這個時候可以選擇使用const關鍵字。在你給一個變量加上const修飾符的同時,通常需要對它進行初始化,在之后的程序中就不能再去改變它.
const修飾符的幾個典型作用:
1. const類型定義:指明變量或對象的值是不能被更新,引入目的是為了取代預編譯指令
2. 可以保護被修飾的東西,防止意外的修改,增強程序的健壯性;
3. 編譯器通常不為普通const常量分配存儲空間,而是將它們保存在符號表中,這使得它成為一個編譯期間的常量,沒有了存儲與讀內存的操作,使得它的效率也很高。
4. 可以節(jié)省空間,避免不必要的內存分配。
使用const的直接的作用就是讓更多的邏輯錯誤在編譯期被發(fā)現(xiàn)。所以我們要盡可能的多使用const。
當const 和 指針斯混在一起的時候,就會很蛋疼。
在此對于判斷const的修飾對象給出一種常使用的方法,我們以*為界線,如果const位于*的左側,則const就是用來修飾指針所指向的變量,即指針指向為常量;如果const位于*的右側,const就是修飾指針本身,即指針本身是常量。
比如:
const int *p;
int const *q;
int * const r= &n;
p和q都是一樣,兩個指針,指向的變量為常量,r本身是一個常量,不能再指向其他位置。
參考
語言中auto,register,static,const,volatile,extern的區(qū)別 - http://blog.csdn.net/sdwuyulunbi/article/details/8469058
C語言變量存儲類型auto static extern static extern register - http://7008965.blog.51cto.com/6998965/1179780
C語言的那些小秘密 - http://blog.csdn.net/bigloomy/article/details/6595197
《C語言深度剖析》
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。