寥寥數筆,記錄我的C語言盲點筆記,只為曾經經歷過,亦有誤,可交流。
1.implict declartion of function 指的是在預處理時沒有函數的申明,但該函數在別的函數中進行了編譯與調用,編譯可以完成鏈接但是會給出warning,需要提前申明
2. sizeof是一個operand操作符,不能直接對其進行&取地址操作。是一個編譯器自動算大小的函數,在預處理時。和宏定義有所類似。sizeof當然不是函數,它是編譯的時候處理的
編譯時,編譯器推斷出sizeof參數的類型,sizeof根據這個類型確定一個整數,所以它可以當常量使用
函數肯定不能當常量使用,函數只能運行時求值
3.1.C語言中,對結構體指針賦值為NULL時,在未對其進行再次修改前,不允許對該結構體取值,因為NULL=0,取0處的內容,程序運行時會出現段錯誤Segmentation fault,不要對NULL地址取值。這個錯誤使得在調用需要指針的函數的最好不要傳入指針變量,除非自帶獲取過一個地址如malloc,calloc等,不然這個地址默認是0,一旦在函數內部發生取值賦值時,就會出現段錯誤。段錯誤往往是有對內存的不正當操作引起,使的程序在運行是侵占內存,系統檢測到後強制終止程序運行,以防止系統死機。
2.在使用malloc使要確定是否分配所需的內存大小,不然程序訪問超出的那些內存時往往不在是你原本想象的數值,系統已經將這些內存自我實現了回收機制,只留下你申請的那部分。也許你能再次訪問到這塊內存,但是最終的結果肯定是內存已經回收清空,系統這樣做的好處就是看不是堆內存鏈表中的區域,自行回收,使系統更高效。
4.C語言中優良的編程習慣#ifndef _H_FINGER_API_H_
#define _H_FINGER_API_H_
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
extern "C" }
#endif
這樣的好處在於定義的頭文件在一個c源文件中出現多次時,也不會出現重復的函數申明,同時這個也可以將c很方便的移植到c++去中去。
5 C語言中,對結構體指針賦值為NULL時,在未對其進行再次修改前,不允許對該結構體取值,因為NULL=0,取0處的內容,程序運行時會出現段錯誤Segmentation fault,
不要對NULL地址取值。
6,for(n = 0 ; n < nLen ; n++)和for(int n = 0 ; n < nLen ; n++)這兩個的區別在與後者的n只能在for這個區域中生效,前者在整個函數域內有效。後者的n不能在for外部使用。c中前者的使用較為理想。C99的標准
7,函數間數據的傳遞也可以考慮使用memcpy來對臨時緩存進行拷貝。但是要記得不能在函數內部把一個臨時緩存區的地址覆給一個傳入的指針變量。因為結束後這部發內容被清空,無意義(除非用malloc申請的內容)
8.全局變量可不可以定義在可被多個.C文件包含的.,h頭文件中?為什麼?恩,不可以在多個.c文件使用含有全局變量(已經定義即初始化)的.h文件,因為每個文件域都有了這個全局變量後。在編譯連接時,編譯器識別到兩個全局變量並且都要分配地址,這樣的話在放入全局變量區之前就出現連接報錯。解決方法:1.在.h中申明為extern int a 或者在其他。c文件文件中聲明extern int a。這樣這個全局變量編譯時就不會報錯但是這個如果只有在一個.c文件中出現定義define或者初始化時,而其他.c只是申明的話,那麼這個全局變量就不會報錯。一般如果變量定義了就會分配內存的。出現多個申明,默認找已經定義的那個作為全局數值。2.對兩個相同的變量都加static,就可以。因為只在自己的文件域內有效,在函數的用法也類似
關鍵是不允許在.h中定義的全局變量兩賦初值(即定義)!,因為.h中賦值後,多個文件一旦使用,就相當與重復了兩次變量的初始化賦值。這個不允許。
9.在編碼中。在.h的頭文件中養成只做函數和變量的申明。在.c文件中來具體實現,以及全局變量的定義等等。
10所有未加static前綴的全局變量和函數都具有全局可見性,其它的源文件也能訪問
11Linux下面的文件換行符為\n(0x0a),區別於window下面的\n\r(兩個字節)
Linux下面EOF 為-1二進制文件為0xff.(-1補碼)EOF是文本文件結束的標志。window下在文本文件中,數據是以字符的ASCⅡ代碼值的形式存放,普通字符的ASCⅡ代碼的范圍是32到127(十進制),EOF的16進制代碼為0x1A(十進制為26),因此可以用EOF作為文件結束標志文本方式 和 二進制方式 的不同在於。
1. 文本方式只能讀取不包括控制字符(換行除外)的文件 (<32)
2. 文本方式會對換行執行翻譯。比如windows下,把文件中的/r/n翻譯為/n,把寫入文件的/n翻譯為/r/n;unix下,把文件中的/n翻譯為/n,把寫入文件的/n翻譯為/n。
12.傳入函數的指針如果是需要使用的有必要對其進行NULL檢測。13.C語言中的申明不一定只是申明,int a;系統會給默認的定義值。但是定義int a=1,一定是定義。還有extern int a;則一定是申明,定義在其他地方,這裡只是引用而已。加extern關鍵字的聲明不是定義並且不分配內存(實際上聲明是不分配內存的)。實際上,它只是宣稱了已經在其它文件中定義的變量的名稱和類型。一個變量可以聲明多次,但是只能定義一次。聲明只有在他同樣是定義時才能初始化,因為只有定義才會分配內存
14。在使用數組或者某些結構體前,最好完成對其的初始化{0}.memset或者bzero等,因為在局部函數內部,編譯器分配的棧空間,初始數值並不是為0.需要先初始化為需要的默認值,不然有可能對你後續程序有影響,而造成比如Segmentation fault(常常是對內存操作出現的錯誤比較操作的內容塊小於分配的大小等等)
15missing braces around initialize該問題是在結構提中有多個數組在初始化時,沒有對每一個進行初始化,從而會出現這個錯誤如typedef struct Usr_Info{
unsigned char ID[ID_LEN];
unsigned char Finger[FMD_LEN];
unsigned int finsih_flag;// 1:one usr info get finsihed
}USR_INFO;初始化USR_INFO one = {0},會出現警告,需要對每一部分的數組進行初始化,就這樣{{0}.{0}.0}。C99的特點
16ANSI C說明了三個用於存儲空間動態分配的函數
(1) malloc 分配指定字節數的存儲區。此存儲區中的初始值不確定
(2) calloc 為指定長度的對象,分配能容納其指定個數的存儲空間。該空間中的每一位(bit)都初始化為0
(3) realloc 更改以前分配區的長度(增加或減少)。當增加長度時,可能需將以前分配區的內容移到另一個足夠大的區域,而新增區域內的初始值則不確定
17 a[]用作函數參數,會退化成指針,即和*a一樣,這樣寫看上去上更明確一點
18,static申明的函數被同一文件內的函數調用後,這個非static的函數照樣可以被其他文件的函數調用,從而可以說是間接的進行了調用static函數。
19,怎樣打印long long型數 :printf("%I64u\n",a);或者%I64x.lld打印64位數據類型。unsigned long long :lld,64位long unsigned int: ld = unsigned long int一樣以上是C99中新加的
20。fread(以r讀的方式打開),fwrite(以a追加的方式打開)如果是操作2進制文件則加為rb,ab
21.參數入棧時,不足int的,擴展為int後入棧
比如char(-127)擴展成int(-127)
也就是由 10000001 擴展成 11111111 11111111 11111111 10000001
然後你使用%u,也就是將 11111111 11111111 11111111 10000001 當成 unsigned int 來看,那它當然就是 4294967169 了
22關於類型提升,有符號擴展, 我看了下《Linux C一站式編程》 的15章的3.5節 “編譯器如何處理類型轉換”的最後一段, 裡面最後一段說:
“最後一個例子,把short型轉換成int型,對應表中的“signed integer to signed integer”,轉換之後應該值不變。那怎麼維持值不變呢?是不是在高位補16個0就行了呢?如果原值是-1,十六進制表示就是ffff,要轉成int 型的-1需要變成ffffffff,因此需要在高位補16個1而不是16個0。換句話說,要維持值不變,在高位補1還是補0取決於原來的符號位,這稱為
符號擴展(Sign Extension)。”
這是signed integer to signed integer, 為何signed char轉為unsigned int時 ,也運用了符號擴展??
23宏定義中使用\來屏蔽換行符,這樣後面的內容都可以是該宏定義塊的內容,直到出現換行符後就意味著該宏內容結束。
24. 指針與靜態數組的sizeof操作
指針均可看為變量類型的一種。所有指針變量的sizeof 操作結果均為4。
注意:int *p; sizeof(p)=4;
但sizeof(*p)相當於sizeof(int);
對於靜態數組,sizeof可直接計算數組大小;
例:int a[10];char b[]="hello";
sizeof(a)等於4*10=40;
sizeof(b)等於6;
注意:數組做型參時,數組名稱當作指針使用!!
void fun(char p[])
{sizeof(p)等於4}
25.C語言復合運行:原則是從右向左依次賦值,可以節省內存開銷a*=a;a=-a;a+=a;a/=a,a|=a;a&=a,a^=a;a=~a(取反);負數的取反和變號不一樣。取反對每一位包括符號位做取反操作,取負就是原值變換符合後的補碼,原數是正,則是負數的補碼存在,原數是負,則以正數的原碼存在(正數原碼和補碼一樣)
26. C語言中的volatile告知編譯器,這個變量不要被編譯器優化成寄存器間接訪問變量。無論什麼情況下都要使用直接訪問(防止特殊的改變,常常指的是硬件引起的變換),volatile易失的,不穩定的1. volatile變量可變允許除了程序之外的比如硬件來修改他的內容 2. 訪問該數據任何時候都會直接訪問該地址處內容,即通過cache提高訪問速度的優化被取消。
27 int bit0:1什麼意思
位域是指信息在存儲時,並不需要占用一個完整的字節, 而只需占幾個或一個二進制位。為了節省存儲空間,並使處理簡便,C語言提供了一種數據結構,稱為“位域”或“位段”。所謂“位域”是把一個字節中的二進位劃分為幾個不同的區域,並說明每個區域的位數。每個域有一個域名,允許在程序中按域名進行操作。 這樣就可以把幾個不同的對象用一個字節的二進制位域來表示
typedef union{
unsigned char value;
struct
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
unsigned int bit4:1;
unsigned int bit5:1;
unsigned int bit6:1;
unsigned int bit7:1;
} bit_field;
} PORT;
28 fstat獲取文件的大小等基礎信息,ftruncate改變文件大小
ftruncate(fd,length),改為length的長度