C語言常見問題總結

2021-08-22 13:31:28 字數 4542 閱讀 8166

1.用/* */注釋**在c語言中不是好辦法,尤其是在注釋的**中原先已經有注釋存在,可能會報錯,更好的辦法是用#if 和 #endif;

2.如果有一些宣告需要用於幾個不同的原始檔,可以在乙個單獨的檔案編寫這些宣告,然後用#include命令把這個檔案包含到需要使用這些宣告的原始檔中;

3.標準的c編譯器不會對陣列下標的有效性進行檢查,如果儲存資料超出陣列長度就會儲存在緊隨陣列之後的記憶體位置,這會破壞原有的儲存在這個位置的資料,導致多種結果;

4.null指標是乙個特殊的指標變數,表示不指向任何東西,它可以賦值給乙個指標,用於表示那個指標不指向任何值。對乙個null指標進行解引用操作是非法的,引起的後果因編譯器而異,兩個常見的後果分別是返回記憶體位置零的值和終止程式。

5.在使用指標變數之前,需要對其顯示的初始化,如果知道指標將被初始化為什麼位址,就將他初初始化為什麼位址,否則將其初始化為null。

6.c語言中,不能通過檢查乙個值的位來判斷它的型別,值的型別並非值本身所固有的一種特性,而是取決於他的使用方式。

7.結構體變數是乙個標量,它可以用於其它標量可以使用的任意場合,因此可以把結構體作為引數傳遞給乙個函式,但是往往不這麼做,這樣做效率很低,因為c語言的引數傳值方式要求把引數的乙份拷貝傳遞給函式,這樣這個結構將占用大量的空間。通常的做法是給函式傳遞乙個指向結構的指標,指標比整個結構要小的多。但是向函式傳遞指標的缺陷在於函式現在可以對呼叫程式的結構變數進行修改,如果不希望如此,可以在函式中使用const關鍵字來防止這類修改。

8.編譯器為乙個結構變數的成員分配記憶體時要滿足他們邊界對齊的要求。在實現結構儲存的邊界對齊時,可能會浪費一部分記憶體空間。根據邊界對齊要求降序排列結構成員可以最大限度的減少結構儲存中浪費的記憶體空間。sizeof返回的值包含了結構中浪費的記憶體空間。

9.malloc

malloc函式返回的是一塊向記憶體池申請的連續的記憶體,當記憶體池為空的,malloc會返回乙個null指標,因此對每個從malloc返回的指標進行檢查,確保非null是非常重要的。malloc返回是void *的指標,因此乙個void*可以轉換為其他任何型別的指標,但有的編譯器需要強制轉換。

10.函式只能返回標量值,不能返回陣列。

11.所有用於數值表示式進行求值的巨集定義都應該用這種方式加上括號,避免在使用巨集時,由於引數中的操作符或鄰近的操作符之間不可預料的相互作用。

#define double(x) ((x)*(x))

12.c語言封裝介面注意事項

提供介面,函式引數除了原生型別,其它的全部傳指標。

不要對外暴露鎖,盡量不要讓呼叫者手工分配記憶體。

記憶體管理,需要誰申請就讓誰釋放,如果你的介面內部申請了記憶體供外部使用那麼一定要提供介面讓外部呼叫去釋放記憶體(因為記憶體管理的庫會存在差異)。

所有的陣列必須帶長度。

所有的函式呼叫應該有返回值,所有的錯誤有清晰的描述。

windows下儲存好pdb。

介面中必須有乙個查詢版本號的介面。

不對歷史介面做擴充套件,而是新增新介面。

最後就是寫乙個介面手冊。

13.c語言中如何定義字串?

可以通過字元陣列或字元指標來定義字串,也可以用巨集定義對常量字串進行定義。

char str1 = "helloworld";  // 通過字元陣列來定義字串"helloworld",陣列中每個儲存單元存放乙個字元

char *str2  = "helloworld";  // 通過字元指標來定義字串"helloworld",指標str2指向乙個存放字串"helloworld"的連續位址單元的首位址

#define str3 "helloworld";  // 通過巨集定義來定義字串"helloworld",等價於str3="helloworld"

14.c語言結構體邊界對齊問題

情況一:沒有#pragma pack巨集的情況

邊界對齊遵循的三個原則:

原則1、普通資料成員對齊規則:第乙個資料成員放在offset為0的地方,以後每個資料成員儲存的起始位置要從該成員大小的整數倍開始(比如int在32位機為4位元組,則要從4的整數倍位址開始儲存)。

原則2、結構體成員對齊規則:如果乙個結構裡有某些結構體成員,則該結構體成員要從其內部最大元素大小的整數倍位址開始儲存。(struct a裡存有struct b,b裡有char,int,double等元素,那b應該從8的整數倍開始儲存。)

原則3、結構體大小對齊規則:結構體大小也就是sizeof的結果,必須是其內部成員中最大的對齊引數的整數倍,不足的要補齊。

情況二:如果有#pragma pack巨集,對齊方式按照巨集的定義來

#pragma pack規定的對齊長度,實際使用的規則是:

結構,聯合,或者類的資料成員,第乙個放在偏移為0的地方,以後每個資料成員的對齊,按照#pragma pack指定的數值和這個資料成員自身長度中,比較小的那個進行。

也就是說,當#pragma pack的值等於或超過所有資料成員長度的時候,這個值的大小將不產生任何效果。

而結構整體的對齊,則按照結構體中最大的資料成員 和 #pragma pack指定值 之間,較小的那個進行。

15.位元組序問題

主機位元組序:

不同的cpu有不同的位元組序型別,這些位元組序是指整數在記憶體中儲存的順序,這個叫做主機序。最常見的有兩種 1.big endian:低位元組存高位址,高位元組存低位址 2.little endian:低位元組存低位址,高位元組存高位址

網路位元組序:

網路位元組順序是tcp/ip中規定好的一種資料表示格式,它與具體的cpu型別、作業系統等無關,從而可以保證資料在不同主機之間傳輸時能夠被正確解釋。網路位元組順序採用big endian排序方式。

注:通過對大小端的儲存原理分析可發現,對於 char 型資料,由於其只佔乙個位元組,所以不存在這個問題,這也是一般情況下把資料緩衝區定義成 char 型別 的原因之一。

linux

系統為大小端模式的轉換提供了 4 個函式,輸入 man byteorder 命令可得函式原型:

#include

uint32_t htonl(uint32_t hostlong); 

uint16_t htons(uint16_t hostshort); 

uint32_t ntohl(uint32_t netlong); 

uint16_t ntohs(uint16_t netshort);

s是short

l 是long

h是host

n是network

htonl 表示 host to network long ,用於將主機 unsigned int 型資料轉換成網路位元組順序; 

htons 表示 host to network short ,用於將主機 unsigned short 型資料轉換成網路位元組順序;

ntohs 把unsigned short型別從網路序轉換到主機序

ntohl 把unsigned long型別從網路序轉換到主機序。

16.inaddr_any 轉換過來就是0.0.0.0,泛指本機的意思,也就是表示本機的所有ip,因為有些機子不止一塊網絡卡,多網絡卡的情況下,這個就表示所有網絡卡ip位址的意思。 比如一台電腦有3塊網絡卡,分別連線三個網路,那麼這台電腦就有3個ip位址了,如果某個應用程式需要監聽某個埠,那他要監聽哪個網絡卡位址的埠呢? 如果繫結某個具體的ip位址,你只能監聽你所設定的ip位址所在的網絡卡的埠,其它兩塊網絡卡無法監聽埠,如果我需要三個網絡卡都監聽,那就需要繫結3個ip,也就等於需要管理3個套接字進行資料交換,這樣很繁瑣, 所以出現inaddr_any,你只需繫結inaddr_any,管理乙個套接字就行,不管資料是從哪個網絡卡過來的,只要是繫結的埠號過來的資料,都可以接收到。

17.tcp粘包

發生tcp粘包、拆包主要原因:

應用程式寫入的資料大於套接字緩衝區大小,這將會發生拆包。

應用程式寫入資料小於套接字緩衝區大小,網絡卡將應用多次寫入的資料傳送到網路上,這將會發生粘包。

進行mss(最大報文長度)大小的tcp分段,當tcp報文長度-tcp頭部長度》mss的時候將發生拆包。

接收方法不及時讀取套接字緩衝區資料,這將發生粘包。

如何解決拆包粘包:

既然知道了tcp是無界的資料流,且協議本身無法避免粘包,拆包的發生,那我們只能在應用層資料協議上,加以控制。通常在制定傳輸資料時,可以使用如下方法:

使用帶訊息頭的協議、訊息頭儲存訊息開始標識及訊息長度資訊,服務端獲取訊息頭的時候解析出訊息長度,然後向後讀取該長度的內容。

設定定長訊息,服務端每次讀取既定長度的內容作為一條完整訊息。

設定訊息邊界,服務端從網路流中按訊息編輯分離出訊息內容。

a)先基於第三種方法,假設區分資料邊界的標識為換行符"\n"(注意請求資料本身內部不能包含換行符),資料格式為json,例如下面是乙個符合這個規則的請求包。

\n  

注意上面的請求資料末尾有乙個換行字元(在php中用雙引號字串"\n"表示),代表乙個請求的結束。

b)基於第一種方法,可以制定,首部固定10個位元組長度用來儲存整個資料報長度,位數不夠補0的資料協議

0000000036  

c)基於第一種方法,可以制定,首部4位元組網路位元組序unsigned int,標記整個包的長度

****  

其中首部四位元組*號代表乙個網路位元組序的unsigned int資料,為不可見字元,緊接著是json的資料格式的包體資料。

c 常見問題總結

答 首先,extern是c c 語言中表明函式和全域性變數作用範圍的關鍵字,該關鍵字告訴編譯器,其宣告的函式和變數可以在本模組或其它模組中使用。通常,在模組的標頭檔案中對本模組提供給其它模組引用的函式和全域性變數以關鍵字extern宣告。extern c 是連線申明 linkage declarat...

C語言常見問題

在c語言中,有乙個 流 的概念 流可以分為兩種型別 文字流 檔案 和二進位製流 檔案 文字流是解釋性的,最長可達255個字元 二進位製流是非解釋性的,一次處理乙個字元。在用c語言程式設計的時候,我們都是用 include指令包含型別為 h 的檔案,那麼可以用該指令包含型別不為 h 的檔案嗎?答案是 ...

C語言常見問題

1 嵌入式與微控制器的區別 從軟體上,行業裡經常把晶元中不帶mmu memory management unit記憶體管理單元 從而不支援虛擬位址,只能裸奔或執行rtos 實時作業系統,例如ucos 華為liteos rt thread freertos 的system,叫做微控制器 例如stm32...