c語言裝逼的代碼?C語言是現在大部分流行語言的源起,也是編寫系統軟件的不二之選,C語言的一些細節值得深入探究,我來為大家講解一下關于c語言裝逼的代碼?跟着小編一起來看一看吧!
C語言是現在大部分流行語言的源起,也是編寫系統軟件的不二之選,C語言的一些細節值得深入探究。
1 關于賦值運算符(普通變量和指針變量的賦值)先看C語言代碼和對應的彙編代碼
7: int a = 5;
00401048 mov dword ptr [ebp-4],5
8: int* b = &a;
0040104F lea eax,[ebp-4]
int a = 5; 彙編指令是move,表示将5的二進制序列傳送到a所對應的内存空間。
可以理解為int a ← 5,将值5賦給a。
再看指針變量的賦值:
int* b = &a;
彙編指令是lea,是Load effective address的縮寫——取有效地址,也就是取偏移地址。
可以理解為 b → a,b指向a。
用結構體做單鍊表的結點時,這樣理解更容易理解鍊表指針的移動:
struct pNode* p,p2;
p = p->next;//p指向p的下一個節點空間
p2 = p2->next->next; //p2指向p2的下一個的下一個節點空間
二者的區别在于:為變量賦值是通過賦值表達式在運行期間動态賦值,而為變量賦初值則是在定義變量的同時在編譯時靜态賦值。如對a進行賦值,對b進行賦初值,形式如下。
int a,b=3;
a=2;
為變量賦值占用的是運行時間,而為變量賦初值占用的是編譯時間。
從上面的分析得知,變量不是一定要初始化的,也可以先進行定義,再進行賦值,這和初始化的效果是一樣的。但是如果想提高運行效率,就得對變量進行初始化。
3 const的一點細節編譯器通常不為普通const隻讀變量分配存儲空間,而是将它們保存在符号表中,這使它成為一個編譯期間的值,沒有了存儲與讀内存的操作,使得它的效率也更高。
4 逗号作為運算符和分隔符逗号在C語言中有時可以作為運算符來連接表達式,有時還可以作為分隔符,起到分隔的作用。那麼,該如何區分逗号是運算符還是分隔符呢?
“,”作為分隔符主要用于以下情況:
(1) 變量聲明時,使用逗号分隔多個變量名。
(2) 函數有多個參數時,用逗号分隔參數。
逗号運算符是C語言提供的一種特殊的運算符,用它可以将兩個表達式連接起來。例如,“1 2,4 5”,稱為逗号表達式,也稱為“順序求值運算符”。它的表達式一般形式為“表達式1,表達式2”,執行順序是先計算表達式1的值,再計算表達式2的值。表達式也可以擴展為“表達式1,表達式2,表達式3,…,表達式n”。
c=(a=3,2*a);
是将一個逗号表達式的值賦給變量c,第一個表達式a=3,第二個表達式2*a,計算得到6,因此變量c的值是6。
代碼d=a=b=3,2*a;整個是一個逗号表達式,這裡逗号表達式的值同樣是2*a的值,結果是6。但是變量d的值是在第一個表達式中計算得到的,得到值為3。
在使用逗号運算符的時候,要注意它的優先級和結合順序。逗号運算符優先級最低,丼且是自左至右結合的。
5 自增運算的不同寫法在效率上的一點區别x = x 1,x = 1,x ,這三個表達式哪個執行效率最高?
第一個表達式x=x 1的執行過程是先讀取等号右邊的x的地址,計算x 1的值,然後讀取等号左邊的x的地址,最後将等号右邊的值傳給等号左邊的值。
第二個表達式x =1的執行過程是先讀取等号右邊的x的地址,然後計算x 1的值,最後将得到的值傳給左邊的x,因為x的地址已在前面讀出,故省去了傳值過程;
第三個表達式的執行過程是先讀取x的地址,然後x自增1;
因此,x 的效率最高。
編譯器優化後彙編代碼應該是一樣的。
從彙編來看前自增與後自增的區别:
7: a=c ;
004016AF mov eax,dword ptr [ebp-0Ch]
004016B2 mov dword ptr [ebp-4],eax
004016B5 mov ecx,dword ptr [ebp-0Ch]
004016B8 add ecx,1
004016BB mov dword ptr [ebp-0Ch],ecx
8: b= c;
004016BE mov edx,dword ptr [ebp-0Ch]
004016C1 add edx,1
004016C4 mov dword ptr [ebp-0Ch],edx
004016C7 mov eax,dword ptr [ebp-0Ch]
004016CA mov dword ptr [ebp-8],eax
switch相對于if…else if,具有較高的運行效率。因為switch會在編譯期建立一個跳轉列表,運行時可以根據跳轉列表進行直接跳轉。
在switch語句中,當找到與swith表達式相等的case時,執行case下的語句。case下的所有語句都執行完成後,如果一直沒有break,那麼程序将會執行到下一個case,而不管它的值是否與switch表達式相等,即多個case之間不具有天然的互斥性。要想使程序執行完一個case後的語句,而不進入下一個case,必須使用break語句,使程序退出switch結構。這樣,後面的case也就不執行了。
C語言一個分支的結束是依賴break完成的。case隻決定—序到哪裡執行,而不決定到哪裡結束。結束位置由break來決定,沒有break就一直執行到switch完整結構結束。
所以,case是swithc語句的入口(特殊情況下也可以是default),而由break提供出口(特殊情況下是最後一條case語句的結束塊符号“}”或return。
7 聯合體變量賦初值由于聯合體變量具有所有成員共享一個内存地址的特點,因此為聯合體變量賦初值時隻能給該變量的第一個成員賦初值,其他成員不能賦初值。例如:
union number
{
int i;
char c;
float f;
}m={2};
數組名是一指針常量,所以不能被再次賦值。隻能對其數據元素逐一操作。
數組名做函數參數時退化為指針,在函數體内不能得到其長度。
二維數組名并不能賦給一個二次指針,隻能賦給一個數組指針,或通過強制類型轉換,賦給一個一次指針:
int arr[5][5] = {1,2,3,4,5,6,7,8};
int (*pa)[5] = arr;
int *p = (int*)arr;
cout<<*pa[1] 2<<endl; // 8
cout<<*(p 7)<<endl; // 8
指針變量聲明并指向目标地址時,由類型信息決定目标内存空間的字節長度,當其指向一個n維數組時,其長度信息為一個n-1維數組的字節長度,所以n維數組指針聲明時需要顯式指定除第一維以外的其它長度信息。
指針數組名在語法層面等價于一個二級指針。
9 内在管理函數及庫中一些算法的參數和返回值的void類型malloc、sort等函數的參數和返回值都使用void類型。原因是C是一門強類型語言,又沒有類型模闆機制來做泛型表示。
void指針隻能單純表示地址信息,其附加的類型信息不存在,所以其為一個不完全類型,隻能用于聲明和傳址,當需要解引用或做指針算術運算時,其類型信息附加的字節長度信息不可或缺,所以需有具體類型的強制轉換。
-End-
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!