溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C語言中的auto,register,volatile,extern,static,const

發(fā)布時間:2020-07-16 09:40:43 來源:網(wǎng)絡 閱讀:401 作者:拳四郎 欄目:開發(fā)技術

你能很隨意地說出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); }

運行結果:

C語言中的auto,register,volatile,extern,static,const


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;     } }

在不生命register變量的情況下,運行時間是:

C語言中的auto,register,volatile,extern,static,const


將pi_digits函數(shù)中的sum聲明為register之后,運行結果:

C語言中的auto,register,volatile,extern,static,const


運行時間有明顯的減少。


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; } 

C語言中的auto,register,volatile,extern,static,const


使用匯編的目的是騙過編譯器改變寄存器中變量的值。

在沒有使用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; } 


main.c

#include <stdio.h>  extern int a; extern int fun(int n); int main()  {  	printf("fun: %d\n",fun(a)); 	return 1; } 


C語言中的auto,register,volatile,extern,static,const


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

C語言中的auto,register,volatile,extern,static,const


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語言深度剖析》

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI