中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
熬夜整理的C/C++萬字總結(一)

大家好,我是唐唐!

一. C語言概述

歡迎大家來到c語言的世界,c語言是一種強大的專業(yè)化的編程語言。

1.1 C語言的起源

貝爾實驗室的Dennis Ritchie在1972年開發(fā)了C,當時他正與ken Thompson一起設計UNIX操作系統(tǒng),然而,C并不是完全由Ritchie構想出來的。它來自Thompson的B語言。

1.2 使用C語言的理由

在過去的幾十年中,c語言已成為最流行和最重要的編程語言之一。它之所以得到發(fā)展,是因為人們嘗試使用它后都喜歡它。過去很多年中,許多人從c語言轉而使用更強大的c++語言,但c有其自身的優(yōu)勢,仍然是一種重要的語言,而且它還是學習c++的必經之路。

  • 高效性。c語言是一種高效的語言。c表現(xiàn)出通常只有匯編語言才具有的精細的控制能力(匯編語言是特定cpu設計所采用的一組內部制定的助記符。不同的cpu類型使用不同的匯編語言)。如果愿意,您可以細調程序以獲得最大的速度或最大的內存使用率。
  • 可移植性。c語言是一種可移植的語言。意味著,在一個系統(tǒng)上編寫的c程序經過很少改動或不經過修改就可以在其他的系統(tǒng)上運行。
  • 強大的功能和靈活性。c強大而又靈活。比如強大靈活的UNIX操作系統(tǒng)便是用c編寫的。其他的語言(Perl、Python、BASIC、Pascal)的許多編譯器和解釋器也都是用c編寫的。結果是當你在一臺Unix機器上使用Python時,最終由一個c程序負責生成最后的可執(zhí)行程序。

1.3 C語言標準

1.3.1 K&R C

起初,C語言沒有官方標準。1978年由美國電話電報公司(AT&T)貝爾實驗室正式發(fā)表了C語言。布萊恩·柯林漢(Brian Kernighan) 和 丹尼斯·里奇(Dennis Ritchie) 出版了一本書,名叫《The C Programming Language》。這本書被 C語言開發(fā)者們稱為K&R,很多年來被當作 C語言的非正式的標準說明。人們稱這個版本的 C語言為K&R C。

K&R C主要介紹了以下特色:結構體(struct)類型;長整數(shù)(long int)類型;無符號整數(shù)(unsigned int)類型;把運算符=+和=-改為+=和-=。因為=+和=-會使得編譯器不知道使用者要處理i = -10還是i =- 10,使得處理上產生混淆。

即使在后來ANSI C標準被提出的許多年后,K&R C仍然是許多編譯器的最準要求,許多老舊的編譯器仍然運行K&R C的標準。

1.3.2 ANSI C/C89標準

1970到80年代,C語言被廣泛應用,從大型主機到小型微機,也衍生了C語言的很多不同版本。1983年,美國國家標準協(xié)會(ANSI)成立了一個委員會X3J11,來制定 C語言標準。

1989年,美國國家標準協(xié)會(ANSI)通過了C語言標準,被稱為ANSI X3.159-1989 "Programming Language C"。因為這個標準是1989年通過的,所以一般簡稱C89標準。有些人也簡稱ANSI C,因為這個標準是美國國家標準協(xié)會(ANSI)發(fā)布的。

1990年,國際標準化組織(ISO)和國際電工委員會(IEC)把C89標準定為C語言的國際標準,命名為ISO/IEC 9899:1990 - Programming languages -- C[5]  。因為此標準是在1990年發(fā)布的,所以有些人把簡稱作C90標準。不過大多數(shù)人依然稱之為C89標準,因為此標準與ANSI C89標準完全等同。

1994年,國際標準化組織(ISO)和國際電工委員會(IEC)發(fā)布了C89標準修訂版,名叫ISO/IEC 9899:1990/Cor 1:1994[6]  ,有些人簡稱為C94標準。

1995年,國際標準化組織(ISO)和國際電工委員會(IEC)再次發(fā)布了C89標準修訂版,名叫ISO/IEC 9899:1990/Amd 1:1995 - C Integrity[7]  ,有些人簡稱為C95標準。

1.3.3 C99標準

1999年1月,國際標準化組織(ISO)和國際電工委員會(IEC)發(fā)布了C語言的新標準,名叫ISO/IEC 9899:1999 - Programming languages -- C ,簡稱C99標準。這是C語言的第二個官方標準。

例如:

  • 增加了新關鍵字 restrict,inline,_Complex,_Imaginary,_Bool
  • 支持 long long,long double _Complex,float _Complex 這樣的類型
  • 支持了不定長的數(shù)組。數(shù)組的長度就可以用變量了。聲明類型的時候呢,就用 int a[*] 這樣的寫法。不過考慮到效率和實現(xiàn),這玩意并不是一個新類型。

二、內存分區(qū)

2.1 數(shù)據類型

2.1.1 數(shù)據類型概念

什么是數(shù)據類型?為什么需要數(shù)據類型? 數(shù)據類型是為了更好進行內存的管理,讓編譯器能確定分配多少內存。

我們現(xiàn)實生活中,狗是狗,鳥是鳥等等,每一種事物都有自己的類型,那么程序中使用數(shù)據類型也是來源于生活。

當我們給狗分配內存的時候,也就相當于給狗建造狗窩,給鳥分配內存的時候,也就是給鳥建造一個鳥窩,我們可以給他們各自建造一個別墅,但是會造成內存的浪費,不能很好的利用內存空間。

我們在想,如果給鳥分配內存,只需要鳥窩大小的空間就夠了,如果給狗分配內存,那么也只需要狗窩大小的內存,而不是給鳥和狗都分配一座別墅,造成內存的浪費。

當我們定義一個變量,a = 10,編譯器如何分配內存?計算機只是一個機器,它怎么知道用多少內存可以放得下10?

所以說,數(shù)據類型非常重要,它可以告訴編譯器分配多少內存可以放得下我們的數(shù)據。

狗窩里面是狗,鳥窩里面是鳥,如果沒有數(shù)據類型,你怎么知道冰箱里放得是一頭大象!

數(shù)據類型基本概念:

  • 類型是對數(shù)據的抽象;
  • 類型相同的數(shù)據具有相同的表示形式、存儲格式以及相關操作;
  • 程序中所有的數(shù)據都必定屬于某種數(shù)據類型;
  • 數(shù)據類型可以理解為創(chuàng)建變量的模具: 固定大小內存的別名;

2.1.2 數(shù)據類型別名

typedef unsigned int u32;
typedef struct _PERSON{
 char name[64];
 int age;
}Person;

void test(){
 u32 val; //相當于 unsigned int val;
 Person person; //相當于 struct PERSON person;
}

2.1.3 void數(shù)據類型

void字面意思是”無類型”,void* 無類型指針,無類型指針可以指向任何類型的數(shù)據。

void定義變量是沒有任何意義的,當你定義void a,編譯器會報錯。

void真正用在以下兩個方面:

  • 對函數(shù)返回的限定;
  • 對函數(shù)參數(shù)的限定;
//1. void修飾函數(shù)參數(shù)和函數(shù)返回
void test01(void){
 printf("hello world");
}

//2. 不能定義void類型變量
void test02(){
 void val; //報錯
}

//3. void* 可以指向任何類型的數(shù)據,被稱為萬能指針
void test03(){
 int a = 10;
 void* p = NULL;
 p = &a;
 printf("a:%d\n",*(int*)p);
 
 char c = 'a';
 p = &c;
 printf("c:%c\n",*(char*)p);
}

//4. void* 常用于數(shù)據類型的封裝
void test04(){
 //void * memcpy(void * _Dst, const void * _Src, size_t _Size);
}

2.1.4 sizeof 操作符

sizeof 是 c語言中的一個操作符,類似于++、--等等。sizeof 能夠告訴我們編譯器為某一特定數(shù)據或者某一個類型的數(shù)據在內存中分配空間時分配的大小,大小以字節(jié)為單位。

基本語法:

sizeof(變量);
sizeof 變量;
sizeof(類型);

sizeof 注意點

  • sizeof返回的占用空間大小是為這個變量開辟的大小,而不只是它用到的空間。和現(xiàn)今住房的建筑面積和實用面積的概念差不多。所以對結構體用的時候,大多情況下就得考慮字節(jié)對齊的問題了;
  • sizeof返回的數(shù)據結果類型是unsigned int;
  • 要注意數(shù)組名和指針變量的區(qū)別。通常情況下,我們總覺得數(shù)組名和指針變量差不多,但是在用sizeof的時候差別很大,對數(shù)組名用sizeof返回的是整個數(shù)組的大小,而對指針變量進行操作的時候返回的則是指針變量本身所占得空間,在32位機的條件下一般都是4。而且當數(shù)組名作為函數(shù)參數(shù)時,在函數(shù)內部,形參也就是個指針,所以不再返回數(shù)組的大小;
//1. sizeof基本用法
void test01(){
 int a = 10;
 printf("len:%d\n", sizeof(a));
 printf("len:%d\n", sizeof(int));
 printf("len:%d\n", sizeof a);
}

//2. sizeof 結果類型
void test02(){
 unsigned int a = 10;
 if (a - 11 < 0){
  printf("結果小于0\n");
 }
 else{
  printf("結果大于0\n");
 }
 int b = 5;
 if (sizeof(b) - 10 < 0){
  printf("結果小于0\n");
 }
 else{
  printf("結果大于0\n");
 }
}

//3. sizeof 碰到數(shù)組
void TestArray(int arr[]){
 printf("TestArray arr size:%d\n",sizeof(arr));
}
void test03(){
 int arr[] = { 10, 20, 30, 40, 50 };
 printf("array size: %d\n",sizeof(arr));

 //數(shù)組名在某些情況下等價于指針
 int* pArr = arr;
 printf("arr[2]:%d\n",pArr[2]);
 printf("array size: %d\n", sizeof(pArr));

 //數(shù)組做函數(shù)函數(shù)參數(shù),將退化為指針,在函數(shù)內部不再返回數(shù)組大小
 TestArray(arr);
}

2.1.5 數(shù)據類型總結

  • 數(shù)據類型本質是固定內存大小的別名,是個模具,C語言規(guī)定:通過數(shù)據類型定義變量;
  • 數(shù)據類型大小計算(sizeof);
  • 可以給已存在的數(shù)據類型起別名typedef;
  • 數(shù)據類型的封裝(void 萬能類型);

2.2 變量

2.1.1 變量的概念

既能讀又能寫的內存對象,稱為變量;

若一旦初始化后不能修改的對象則稱為常量。

變量定義形式: 類型  標識符, 標識符, … , 標識符

2.1.2 變量名的本質

  • 變量名的本質:一段連續(xù)內存空間的別名;
  • 程序通過變量來申請和命名內存空間 int a = 0;
  • 通過變量名訪問內存空間;
  • 不是向變量名讀寫數(shù)據,而是向變量所代表的內存空間中讀寫數(shù)據;

修改變量的兩種方式:

  void test(){
 
 int a = 10;

 //1. 直接修改
 a = 20;
 printf("直接修改,a:%d\n",a);

 //2. 間接修改
 int* p = &a;
 *p = 30;

 printf("間接修改,a:%d\n", a);
}

2.3 程序的內存分區(qū)模型

2.3.1 內存分區(qū)

2.3.1.1 運行之前

我們要想執(zhí)行我們編寫的c程序,那么第一步需要對這個程序進行編譯。1)預處理:宏定義展開、頭文件展開、條件編譯,這里并不會檢查語法

2)編譯:檢查語法,將預處理后文件編譯生成匯編文件

3)匯編:將匯編文件生成目標文件(二進制文件)

4)鏈接:將目標文件鏈接為可執(zhí)行程序

?代碼區(qū)

存放 CPU 執(zhí)行的機器指令。通常代碼區(qū)是可共享的(即另外的執(zhí)行程序可以調用它),使其可共享的目的是對于頻繁被執(zhí)行的程序,只需要在內存中有一份代碼即可。代碼區(qū)通常是只讀的,使其只讀的原因是防止程序意外地修改了它的指t令。另外,代碼區(qū)還規(guī)劃了局部變量的相關信息。

?全局初始化數(shù)據區(qū)/靜態(tài)數(shù)據區(qū)(data段)

該區(qū)包含了在程序中明確被初始化的全局變量、已經初始化的靜態(tài)變量(包括全局靜態(tài)變量和t)和常量數(shù)據(如字符串常量)。

?未初始化數(shù)據區(qū)(又叫 bss 區(qū))

存入的是全局未初始化變量和未初始化靜態(tài)變量。未初始化數(shù)據區(qū)的數(shù)據在程序開始執(zhí)行之前被內核初始化為 0 或者空(NULL)。

總體來講說,程序源代碼被編譯之后主要分成兩種段:程序指令(代碼區(qū))和程序數(shù)據(數(shù)據區(qū))。代碼段屬于程序指令,而數(shù)據域段和.bss段屬于程序數(shù)據。

那為什么把程序的指令和程序數(shù)據分開呢?

  • 程序被load到內存中之后,可以將數(shù)據和代碼分別映射到兩個內存區(qū)域。由于數(shù)據區(qū)域對進程來說是可讀可寫的,而指令區(qū)域對程序來講說是只讀的,所以分區(qū)之后呢,可以將程序指令區(qū)域和數(shù)據區(qū)域分別設置成可讀可寫或只讀。這樣可以防止程序的指令有意或者無意被修改;

  • 當系統(tǒng)中運行著多個同樣的程序的時候,這些程序執(zhí)行的指令都是一樣的,所以只需要內存中保存一份程序的指令就可以了,只是每一個程序運行中數(shù)據不一樣而已,這樣可以節(jié)省大量的內存。比如說之前的Windows Internet Explorer 7.0運行起來之后, 它需要占用112 844KB的內存,它的私有部分數(shù)據有大概15 944KB,也就是說有96 900KB空間是共享的,如果程序中運行了幾百個這樣的進程,可以想象共享的方法可以節(jié)省大量的內存。

2.3.1.1 運行之后

程序在加載到內存前,代碼區(qū)和全局區(qū)(data和bss)的大小就是固定的,程序運行期間不能改變。然后,運行可執(zhí)行程序,操作系統(tǒng)把物理硬盤程序load(加載)到內存,除了根據可執(zhí)行程序的信息分出代碼區(qū)(text)、數(shù)據區(qū)(data)和未初始化數(shù)據區(qū)(bss)之外,還額外增加了棧區(qū)、堆區(qū)。

?代碼區(qū)(text segment)

加載的是可執(zhí)行文件代碼段,所有的可執(zhí)行代碼都加載到代碼區(qū),這塊內存是不可以在運行期間修改的。

?未初始化數(shù)據區(qū)(BSS)

加載的是可執(zhí)行文件BSS段,位置可以分開亦可以緊靠數(shù)據段,存儲于數(shù)據段的數(shù)據(全局未初始化,靜態(tài)未初始化數(shù)據)的生存周期為整個程序運行過程。

?全局初始化數(shù)據區(qū)/靜態(tài)數(shù)據區(qū)(data segment)

加載的是可執(zhí)行文件數(shù)據段,存儲于數(shù)據段(全局初始化,靜態(tài)初始化數(shù)據,文字常量(只讀))的數(shù)據的生存周期為整個程序運行過程。

?棧區(qū)(stack)

棧是一種先進后出的內存結構,由編譯器自動分配釋放,存放函數(shù)的參數(shù)值、返回值、局部變量等。在程序運行過程中實時加載和釋放,因此,局部變量的生存周期為申請到釋放該段??臻g。

?堆區(qū)(heap)

堆是一個大容器,它的容量要遠遠大于棧,但沒有棧那樣先進后出的順序。用于動態(tài)內存分配。堆在內存中位于BSS區(qū)和棧區(qū)之間。一般由程序員分配和釋放,若程序員不釋放,程序結束時由操作系統(tǒng)回收。

2.3.2 分區(qū)模型

2.3.2.1 棧區(qū)

由系統(tǒng)進行內存的管理。主要存放函數(shù)的參數(shù)以及局部變量。在函數(shù)完成執(zhí)行,系統(tǒng)自行釋放棧區(qū)內存,不需要用戶管理。

#char* func(){
 char p[] = "hello world!"; //在棧區(qū)存儲 亂碼
 printf("%s\n", p);
 return p;
}
void test(){
 char* p = NULL;
 p = func();  
 printf("%s\n",p); 
}

2.3.2.2 堆區(qū)

由編程人員手動申請,手動釋放,若不手動釋放,程序結束后由系統(tǒng)回收,生命周期是整個程序運行期間。使用malloc或者new進行堆的申請。

char* func(){
 char* str = malloc(100);
 strcpy(str, "hello world!");
 printf("%s\n",str);
 return str;
}

void test01(){
 char* p = NULL;
 p = func();
 printf("%s\n",p);
}

void allocateSpace(char* p){
 p = malloc(100);
 strcpy(p, "hello world!");
 printf("%s\n", p);
}

void test02(){
 
 char* p = NULL;
 allocateSpace(p);

 printf("%s\n", p);
}

堆分配內存API:

#include <stdlib.h>
void *calloc(size_t nmemb, size_t size);

功能:

在內存動態(tài)存儲區(qū)中分配nmemb塊長度為size字節(jié)的連續(xù)區(qū)域。calloc自動將分配的內存置0。

參數(shù):

nmemb:所需內存單元數(shù)量 size:每個內存單元的大小(單位:字節(jié))

返回值:

成功:分配空間的起始地址

失?。篘ULL

#include <stdlib.h>
void *realloc(void *ptr, size_t size);

功能:

重新分配用malloc或者calloc函數(shù)在堆中分配內存空間的大小。realloc不會自動清理增加的內存,需要手動清理,如果指定的地址后面有連續(xù)的空間,那么就會在已有地址基礎上增加內存,如果指定的地址后面沒有空間,那么realloc會重新分配新的連續(xù)內存,把舊內存的值拷貝到新內存,同時釋放舊內存。

參數(shù):

ptr:為之前用malloc或者calloc分配的內存地址,如果此參數(shù)等于NULL,那么和realloc與malloc功能一致

size:為重新分配內存的大小, 單位:字節(jié)

返回值:

成功:新分配的堆內存地址

失?。篘ULL

void test01(){
 
 int* p1 = calloc(10,sizeof(int));
 if (p1 == NULL){
  return;
 }
 for (int i = 0; i < 10; i ++){
  p1[i] = i + 1;
 }
 for (int i = 0; i < 10; i++){
  printf("%d ",p1[i]);
 }
 printf("\n");
 free(p1);
}

void test02(){
 int* p1 = calloc(10, sizeof(int));
 if (p1 == NULL){
  return;
 }
 for (int i = 0; i < 10; i++){
  p1[i] = i + 1;
 }

 int* p2 = realloc(p1, 15 * sizeof(int));
 if (p2 == NULL){
  return;
 }

 printf("%d\n", p1);
 printf("%d\n", p2);

 //打印
 for (int i = 0; i < 15; i++){
  printf("%d ", p2[i]);
 }
 printf("\n");

 //重新賦值
 for (int i = 0; i < 15; i++){
  p2[i] = i + 1;
 }
 
 //再次打印
 for (int i = 0; i < 15; i++){
  printf("%d ", p2[i]);
 }
 printf("\n");

 free(p2);
}

2.3.2.3 全局/靜態(tài)區(qū)

全局靜態(tài)區(qū)內的變量在編譯階段已經分配好內存空間并初始化。這塊內存在程序運行期間一直存在,它主要存儲全局變量、靜態(tài)變量和常量。

注意:

(1)這里不區(qū)分初始化和未初始化的數(shù)據區(qū),是因為靜態(tài)存儲區(qū)內的變量若不顯示初始化,則編譯器會自動以默認的方式進行初始化,即靜態(tài)存儲區(qū)內不存在未初始化的變量。

(2)全局靜態(tài)存儲區(qū)內的常量分為常變量和字符串常量,一經初始化,不可修改。靜態(tài)存儲內的常變量是全局變量,與局部常變量不同,區(qū)別在于局部常變量存放于棧,實際可間接通過指針或者引用進行修改,而全局常變量存放于靜態(tài)常量區(qū)則不可以間接修改。

(3)字符串常量存儲在全局/靜態(tài)存儲區(qū)的常量區(qū)。

int v1 = 10;//全局/靜態(tài)區(qū)
const int v2 = 20; //常量,一旦初始化,不可修改
static int v3 = 20; //全局/靜態(tài)區(qū)
char *p1; //全局/靜態(tài)區(qū),編譯器默認初始化為NULL

//那么全局static int 和 全局int變量有什么區(qū)別?

void test(){
 static int v4 = 20; //全局/靜態(tài)區(qū)
}
char* func(){
 static char arr[] = "hello world!"; //在靜態(tài)區(qū)存儲 可讀可寫
 arr[2] = 'c';
 char* p = "hello world!"; //全局/靜態(tài)區(qū)-字符串常量區(qū) 
 //p[2] = 'c'; //只讀,不可修改 
 printf("%d\n",arr);
 printf("%d\n",p);
 printf("%s\n", arr);
 return arr;
}
void test(){
 char* p = func();
 printf("%s\n",p);
}

2.3.2.4 總結

在理解C/C++內存分區(qū)時,常會碰到如下術語:數(shù)據區(qū),堆,棧,靜態(tài)區(qū),常量區(qū),全局區(qū),字符串常量區(qū),文字常量區(qū),代碼區(qū)等等,初學者被搞得云里霧里。在這里,嘗試捋清楚以上分區(qū)的關系。

數(shù)據區(qū)包括:堆,棧,全局/靜態(tài)存儲區(qū)。

  • 全局/靜態(tài)存儲區(qū)包括:常量區(qū),全局區(qū)、靜態(tài)區(qū)。
  • 常量區(qū)包括:字符串常量區(qū)、常變量區(qū)。
  • 代碼區(qū):存放程序編譯后的二進制代碼,不可尋址區(qū)。

可以說,C/C++內存分區(qū)其實只有兩個,即代碼區(qū)和數(shù)據區(qū)。

2.3.3 函數(shù)調用模型

2.3.3.1 函數(shù)調用流程

棧(stack)是現(xiàn)代計算機程序里最為重要的概念之一,幾乎每一個程序都使用了棧,沒有棧就沒有函數(shù),沒有局部變量,也就沒有我們如今能見到的所有計算機的語言。在解釋為什么棧如此重要之前,我們先了解一下傳統(tǒng)的棧的定義:

在經典的計算機科學中,棧被定義為一個特殊的容器,用戶可以將數(shù)據壓入棧中(入棧,push),也可以將壓入棧中的數(shù)據彈出(出棧,pop),但是棧容器必須遵循一條規(guī)則:先入棧的數(shù)據最后出棧(First In Last Out,FILO).

在經典的操作系統(tǒng)中,??偸窍蛳略鲩L的。壓棧的操作使得棧頂?shù)牡刂窚p小,彈出操作使得棧頂?shù)刂吩龃蟆?/p>

棧在程序運行中具有極其重要的地位。最重要的,棧保存一個函數(shù)調用所需要維護的信息,這通常被稱為堆棧幀(Stack Frame)或者活動記錄(Activate Record).一個函數(shù)調用過程所需要的信息一般包括以下幾個方面:

  • 函數(shù)的返回地址;
  • 函數(shù)的參數(shù);
  • 臨時變量;
  • 保存的上下文:包括在函數(shù)調用前后需要保持不變的寄存器。

我們從下面的代碼,分析以下函數(shù)的調用過程:

int func(int a,int b){
 int t_a = a;
 int t_b = b;
 return t_a + t_b;
}

int main(){
 int ret = 0;
 ret = func(10, 20);
 return EXIT_SUCCESS;
}

2.3.3.2 調用慣例

現(xiàn)在,我們大致了解了函數(shù)調用的過程,這期間有一個現(xiàn)象,那就是函數(shù)的調用者和被調用者對函數(shù)調用有著一致的理解,例如,它們雙方都一致的認為函數(shù)的參數(shù)是按照某個固定的方式壓入棧中。如果不這樣的話,函數(shù)將無法正確運行。

如果函數(shù)調用方在傳遞參數(shù)的時候先壓入a參數(shù),再壓入b參數(shù),而被調用函數(shù)則認為先壓入的是b,后壓入的是a,那么被調用函數(shù)在使用a,b值時候,就會顛倒。

因此,函數(shù)的調用方和被調用方對于函數(shù)是如何調用的必須有一個明確的約定,只有雙方都遵循同樣的約定,函數(shù)才能夠被正確的調用,這樣的約定被稱為”調用慣例(Calling Convention)”.一個調用慣例一般包含以下幾個方面:

函數(shù)參數(shù)的傳遞順序和方式

函數(shù)的傳遞有很多種方式,最常見的是通過棧傳遞。函數(shù)的調用方將參數(shù)壓入棧中,函數(shù)自己再從棧中將參數(shù)取出。對于有多個參數(shù)的函數(shù),調用慣例要規(guī)定函數(shù)調用方將參數(shù)壓棧的順序:從左向右,還是從右向左。有些調用慣例還允許使用寄存器傳遞參數(shù),以提高性能。

棧的維護方式

在函數(shù)將參數(shù)壓入棧中之后,函數(shù)體會被調用,此后需要將被壓入棧中的參數(shù)全部彈出,以使得棧在函數(shù)調用前后保持一致。這個彈出的工作可以由函數(shù)的調用方來完成,也可以由函數(shù)本身來完成。

為了在鏈接的時候對調用慣例進行區(qū)分,調用慣例要對函數(shù)本身的名字進行修飾。不同的調用慣例有不同的名字修飾策略。

事實上,在c語言里,存在著多個調用慣例,而默認的是cdecl.任何一個沒有顯示指定調用慣例的函數(shù)都是默認是cdecl慣例。比如我們上面對于func函數(shù)的聲明,它的完整寫法應該是:

int _cdecl func(int a,int b);

注意: cdecl不是標準的關鍵字,在不同的編譯器里可能有不同的寫法,例如gcc里就不存在_cdecl這樣的關鍵字,而是使用__attribute_((cdecl)).

2.3.3.2 函數(shù)變量傳遞分析

2.3.4 棧的生長方向和內存存放方向

//1. 棧的生長方向
void test01(){

 int a = 10;
 int b = 20;
 int c = 30;
 int d = 40;

 printf("a = %d\n", &a);
 printf("b = %d\n", &b);
 printf("c = %d\n", &c);
 printf("d = %d\n", &d);

 //a的地址大于b的地址,故而生長方向向下
}

//2. 內存生長方向(小端模式)
void test02(){
 
 //高位字節(jié) -> 地位字節(jié)
 int num = 0xaabbccdd;
 unsigned char* p = &num;

 //從首地址開始的第一個字節(jié)
 printf("%x\n",*p);
 printf("%x\n", *(p + 1));
 printf("%x\n", *(p + 2));
 printf("%x\n", *(p + 3));
}
本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
《C++中類對象的內存布局和占用空間》《C++ 類里面,函數(shù)占用存儲空間問題 》 demo...
關于指針變量在內存中所在的長度(轉載)
C語言為指針動態(tài)分配內存
在線學習-第八章 指針 8.6.2 指針作為函數(shù)的返回值
C語言經典筆試題(一)
c++之指針作為函數(shù)參數(shù)傳遞的問題
更多類似文章 >>
生活服務
熱點新聞
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服