有趣的c語言

寫在前面

工作三年多,常聽各位前輩講:

語言是其次的,重要的是思想。

深以爲然,於是繼續貫徹陶淵明的:

好讀書,不求甚解。

結果,工作了三年多,稀裏糊塗的代碼寫了不少,犯的錯誤也很多,吃一塹長一智的過程中,也會經常有很多不解:“這樣寫,難道不對麼?”

最近終於有時間,終於還是決定花點時間,把c語言掌握的清晰一點,選中了這本已經帶領無數大神走向巔峯的神書《c專家編程》,打算通讀一遍,空口無憑,記個筆記,所以,到這裏您可以返回了,這,只不過是一個簡陋的讀書筆記。。。

01 #define中的空格

記得最開始學習編程的時候,有聽過一些說法,宏定義中的空格實際上沒有作用,例如:

//01-1.1
#include <stdio.h>    
                                                                                                                                                          
#define sum(a, b)       ((a) + (b))                                                                                                                                             
#define sum_1(a, b)     ((a)+(b))                                                                                                                                                                                                                                                                                                                 
#define sum_2(a,b) ((a)+(b))                                                                                                                                                    
                                                                                                                                                                                
int main(int argc, char* argv[])                                                                                                                                                
{                                                                                                                                                                               
    printf("sum = %d\n", sum(1, 1));                                                                                                                                            
    printf("sum_1 = %d\n", sum_1(1, 1));                                                                                                                                        
    printf("sum_2 = %d\n", sum_2(1, 1));                                                                                                                                        
    return 0;                                                                                                                                                                   
}          

預編譯後的產物,其實是這樣的:

//01-1.2
//...不相關,省略

int main(int argc, char* argv[])
{
 printf("sum = %d\n", ((1) + (1)));
 printf("sum_1 = %d\n", ((1)+(1)));
 printf("sum_2 = %d\n", ((1)+(1)));
 return 0;
}

上面的空格的確不會影響結果輸出,而且,行尾多加的幾個空格也沒有什麼用處,然而另外一些情況,顯然不是如此:

//01-2.1.1
#define a(y) a_expanded(y)

int a_expanded(int y)
{
        return y + 10;
}

int main(int argc, char* argv[])
{
        int x = 100;

        a(x);
        return 0;
}

預編譯後如下:

//01-2.1.2
//...不相關,省略

int main(int argc, char* argv[])
{
 int x = 100;

 a_expanded(x);
 return 0;
}

而下面這段代碼,加了兩個空格之後,含義卻完全不同:

//01-2.2.1
#define a (y) a_expanded (y)

int a_expanded(int y)
{
        return y + 10;
}

int main(int argc, char* argv[])
{
        int x = 100;

        a(x);
        return 0;
}

預編譯後的產物卻是這樣:

//01-2.2.2
//...不相關,省略

int main(int argc, char* argv[])
{
 int x = 100;

 (y) a_expanded (y)(x);
 return 0;
}

那麼顯然,空格影響了宏定義的含義,當然,代碼01-2.2.1實際上無法執行,因此,宏定義中,顯然還是要小心的注意某些位置空格的問題。

02 const修飾的是誰?

int foo(const char** p)                                                                                                                                                         
{                                                                                                                                                                                                                                                                                                                                             
}                                                                                                                                                                               
                                                                                                                                                                                
int main(int argc, char** argv)                                                                                                                                                 
{                                                                                                                                                                               
    foo(argv);                                                                                                                                                                  
}                 

上面這段例子裏,編譯會報warning:

const.c: In function ‘main’:
const.c:8:9: warning: passing argument 1 of ‘foo’ from incompatible pointer type [-Wincompatible-pointer-types]
     foo(argv);
         ^~~~
const.c:1:5: note: expected ‘const char **’ but argument is of type ‘char **’
 int foo(const char** p)
     ^~~

那麼顯然,編譯器認爲,char**並不能直接複製給const char **,會發生隱式類型轉換,可是,下面的例子卻很常見:

int foo(const char* p)                                                                                                                                                          
{         
}                                                                                                                                                                                
int main(int argc, char* argv)                                                                                                                                                  
{                                                                                                                                                                               
    foo(argv);                                                                                                                                                                  
}                                                                                                                                                                               

那麼,一個簡單的問題就是,c語言的參數傳遞實際上是一個賦值過程,那麼char*可以賦值給const char*,爲什麼char **不能賦值給const char**

兩個操作數都是指向有限定符或無限定符的相容類型的指針,左邊指針所指向的類型必須包含右邊指針所指向類型的全部限定符。

那麼,上面主要有兩處需要注意:

  1. 賦值的左右兩邊必須類型相容。
  2. 左邊必須包含右邊的全部限定符。

根據這兩個條件,解釋以下這個問題:
char*是一個指向沒有限定符char類型的指針。
const char*是一個有const限定符char類型的指針。
char類型相容,左邊包含右邊的限定符,因此可以賦值。

char**是一個指向char類型的指針的指針。
const char**是一個指向有const限定符限制的char類型的指針的指針。
那麼顯然,二者均沒有限定符,且是指針,前者指向char*,後者指向const char*,二者不相容,也因此,char**實際上與const char**不相容,因此,上面的編譯會報warning。

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