純屬個人的C語言零散筆記

1,如果參數是指針,並且僅僅輸入參數用,則應該在類型前加const,以防止該指針在函數體內被意外修改
   例如:void str_copy(char * strDestination,const char * strSource);

2,返回語句不可返回指向“棧內存”的“指針”,因爲該內存在函數體結束時被自動銷燬
例如:
char * Func(void)
{
   char str [30];
   ...
   return str;
}
str屬於局部變量,位於棧內存中,在Func結束的時候被釋放,所以返回str將導致錯誤.

 

3,在函數體的“入口處”,對參數的有效性進行檢查。尤其是指針參數,儘量使用斷言宏做入口校驗,而不使用如句語校驗。

 

assert (NULL!= str);

 


4,參數命名要恰當,順序要合理
例如str_copy,它有兩個參數。如果參數名字起爲str1和str2,例如
   void str_copy(char * str1,char * str2);
那麼我們很難搞清楚究竟是把STR1拷貝到STR2中,還是剛好倒過來。
可以把參數名字起得更有意義,如叫strSource和strDestination。這樣從名字上就可以看出應該把strSource拷貝到strDestination。
還有一個問題,這兩個參數那一個該在前那一個該在後?參數的順序要遵循程序員的習慣。一般地,應將目的參數放在前面,源參數放在後面。如果將函數聲明爲:

 

   void str_copy(char * strSource,char * strDestination);

 

別人在使用時可能會不假思索地寫成如下形式:

   char str [20];
   str_copy(str,“Hello World”); 參數順序顛倒
   
5,靜態區,棧,堆
靜態區:保存自動全局變量和靜態變量(包括靜態的全局和局部變量)靜態區的內容在總個個程序的生命週期內都存在,由編譯器在編譯的時候分配。
棧:保存局部變量棧上的內容只在函數的範圍內存在,當函數運行結束,這些內容也會自動被銷燬其特點是效率高,但空間大小有限。
堆:由的malloc系列函數或新操作符分配的內存其生命週期由免費或刪除決定在沒有釋放之前一直存在,直到程序結束其特點是使用靈活,空間比較大,但容易出錯。


6,防止頭文件被重複包含
如下例:
   #ifndef __FN_FILENAME_H
   #define __FN_FILENAME_H
   ...
   #endif

 

其中“FN_FILENAME”一般爲本頭文件名大寫,這樣可以有效避免重複,因爲同一工程中不可能存在兩個同名的頭文件。

 

7,結構體內存對齊

編譯器爲了提高訪問速度,會對結構體進行分組訪問,也就是結構體內存對齊。在結構體聲明時需要注意排列變量的聲明順序以減少不必要的內存佔用。在某些特定情況下不需要內存對齊,可以使用預編譯指令#pragma pack(1)和#pragma pack()將不想內存對齊的結構體包在其中

#pragma pack(1)

結構體聲明;

#pragma pack()

8,C語言中不存在泛型,但是可以使用void*來實現

//一般實現
void swap(int *x,int *y)
{
    int tmp = *x;
    *x = *y;
    *y = tmp;
}
main()
{
    int a=1,b=2;
    swap(&a,&b)
}
//以上的swap函數只適合int類型的變量交換,其他類型需要重新定義
//通過void* 實現泛式
void swap(void *x,void *y,int size)
{
    void *p_tmp = (void*)malloc(size);
    
    memcpy(p_tmp,x,size);
    memcpy(x,y,size);
    memcpy(y,p_tmp,size);
    
    free(p_tmp);
}

main()
{
    int a=1,b=2;
    swap(&a,&b,sizeof(int));
    float c=3,d=4;
    swap(&c,&d,sizeof(float));

}

9,函數聲明 

函數聲明時只要給出返回值類型、函數名、參數類型即可;

故一般函數聲明 int function(int x,int y),也可以寫成 int function(int,int);

10,C語言##連接符和#符的使用

在宏定義裏,a##b就是把a,b聯接起來,
比如f(1,2)就是12,但是是數。
#a就是把a轉化成字串,併合並。
所以 printf("%s\n",g(f(1,2)));就直接把f(1,2)轉成字串了。

#define A(x) T_##x
#define B(x) #@x
#define C(x) #x
我們假設:x=1,則有:
A(1)------〉T_1
B(1)------〉'1'
C(1)------〉"1"

 

11、memset結構體 

typedef struct {
     uint8_t                 buf[256];
     uint32_t                length;                    //數據長度
} UART_POLL_BUF;

//結構體
UART_POLL_BUF poll_buff;
memset(&poll_buff,0x00,sizeof(UART_POLL_BUF ));
//結構體數組
UART_POLL_BUF poll2_buff[10];
memset(&poll_buff,0x00,sizeof(UART_POLL_BUF )*10);

12、無符號字符 uint8 變量移位問題

#include "stdio.h"
int main()
{
	unsigned char a = 1;

    printf("a = %d\n",a);
    printf("(a<<8)= %d\n",a<<8);
   printf("a = %d\n",a<<=8);

   return 0;
}

輸出結果:

a = 1
(a<<8)= 256
a = 0

C標準規定在進行位運算時,a<<8這個表達式,a運算時會被類型提升爲int。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章