C語言拾遺


1. 沒C++那么惡心的const

 

C語言中的const修飾符用於修飾一個變量是const屬性的。被C語言的const修飾的變量具有只讀屬性,並且不能被修改。

const修飾的變量 != 常量,const修飾的變量雖然不能別修改,但是和常量還是有本質的區別的。

在定義const類型的變量的時候,必須進行初始化,當然,在const作為函數的參數的時候,是不需要初始化的。

1.1編譯器對const變量的優化:

 

編譯器通常不為普通const 只讀變量分配存儲空間,而是將它們保存在符號表中,這使得它成為一個編譯期間的值,沒有了存儲與讀內存的操作,使得它的效率也很高。

const 定義的只讀變量從匯編的角度來看,只是給出了對應的內存地址,而不是象#define一樣給出的是立即數,所以,const定義的只讀變量在程序運行過程中只有一份拷貝(因為它是全局的只讀變量,存放在靜態區),而#define定義的宏常量在內存中有若干個拷貝。#define宏是在預編譯階段進行替換,而const修飾的只讀變量是在編譯的時候確定其值。#define宏沒有類型,而const修飾的只讀變量具有特定的類型。

1.2當typedef碰到變量修飾符(const)

 

typedef struct student
{
    /*code*/
}Stu_st,*Stu_pst;

1)const Stu_pst stu3;
2)Stu_pst const stu4;

 

對於定義的stu3 和stu4,它們的類型一樣嗎?答案是一樣的。為什么?

在這里我們不能想當然的認為typedef和#define一樣,直接進行展開。實際上,因為const修飾的都是變量自身,const對變量進行修飾的時候,不考慮類型,也就是說1)和2)中的typedef類型都被認為是一個類型,而不是被展開。所以上述就相當於是:

const type var
      type const var

也就是說,const修飾的是變量var。

2. 不多見的volatile

 

volatile 關鍵字和const 一樣是一種類型修飾符,用它修飾的變量表示可以被某些編譯器未知的因素更改,比如操作系統、硬件或者其它線程等。遇到這個關鍵字聲明的變量,編譯器對訪問該變量的代碼就不再進行優化,從而可以提供對特殊地址的穩定訪問。

 

3. 結構體

 

3.1 柔性數組

柔性數組又稱為0長數組(zero-length arrays),這是C99加進去的一個特性。可以這樣定義一個柔性數組:

struct line {
       int length;
       char contents[];
};
     
struct line *thisline = (struct line *) malloc (sizeof (struct line) + this_length);
thisline->length = this_length;

在ISO C90中,在定義一個類似於柔性數組(在C90標准中還沒有柔性數組的概念)的結構體成員的時候,contents[]在定義的時候需要定義成這樣:contents[0],其中的0是必須的。

在ISO C99中,可以直接在結構體中定義一個自由數組成員,自由數組的語法如下:

  • 自由數組成員的長度為0,在定義一個數組的個數的時候,[]中的0不被包括。
  • 自由數組成員是不完全類型,所以對結構體使用sizeof操作符時不會包括自由數組成員的大小
  • 在一個自由數組前必須定義至少一個成員,不能在一個結構體中只定義一個自由數組。
  • 一個結構體如果包含了一個自由數組,或者在一個聯合中包含了這種結構體,那么這種結構體或者聯合不能成為結構體的成員或者是一個數組的成員。

關於GCC對柔性數組的支持,可以訪問這個網站:http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html#Zero-Length

 

4. 在解析表達式時的貪心法則

 

對於這樣一個表達式:

a+++b

到底表示的是什么呢?是a+ (++b)還是(a++) +b?這個就需要考慮C語言在語法分析的時候是以什么方式解析的。

在C語言的編譯器進行語法分析的時候,使用的是貪心法則。也就是說在處理表達式的時候,如果當前的字符可以和前一個字符串組成一個有意義的符號,則繼續讀入下一個字符,直到無法組成一個有意義的字符。

也就說對於上述的表達式,在解析到a+后碰到了+,這個時候,由於a++在C語言中是合法的,那么它繼續處理下一個+,由於a+++在C語言中是非法的,那么就不把+作為表達式的一部分,也就說上述的表達式就被解析為:(a++) + b。

 

5. 預處理

 

在編譯的時候可以使用的一些指令,用於在編譯的時候輸出一些有用的信息,便於追蹤編譯過程,以及控制編譯。

#line    //改變當前的行數和文件名稱,基本語法如下:#line number["filename"]

#error   //編譯程序時,如果遇到#error就會產生一個編譯錯誤提示信息,並停止編譯。

 

編譯器在編譯過程預定義了一些宏,用於輸出一些編譯過程的信息:

_LINE_        //編譯器正在編譯的行號
_FILE_           //編譯器正在變異的文件名
_TIME_           //編譯的時間
_STDC_        //判斷該文件是不是定義成標准C程序

 

 


參考:《C語言深度剖析》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM