程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 我學C的那些年[ch02]:宏,結構體,typedef,ch02typedef

我學C的那些年[ch02]:宏,結構體,typedef,ch02typedef

編輯:關於C語言

我學C的那些年[ch02]:宏,結構體,typedef,ch02typedef


c語言的編譯過程:

  • 預處理
  • 編譯
  • 匯編
  • 鏈接

    而預處理中有三種情況:

  • 文件包含( #include )
  • 條件編譯(#if,#ifndef,#endif)
  • 宏定義( #define )

    宏就是預處理中的一種情況. 其實,宏的概念就是文本替換

     

    宏的作用:

    1.可維護性

    2.可讀性

    宏還有其他作用比如:程序調試跟蹤  等, 因為我也沒試過那些,這裡不寫那些了

  •  

     

     

    宏定義:

    1.不帶參數的宏定義

    #define 標識符  字符串

    2.帶參數的宏定義

    #define 標識符(參數表) 字符串

    注意:標識符一般大寫  ,

    這裡將不會解答宏中包含特殊符號:#、##的問題.

     

     

    1.不帶參數的宏:

    源文件:C:\Users\Zero\Desktop\c\temp\macro.c

    #include
     <stdio.h>
    
    #define PI 3.1415    //定義常量PI
    
    void main(){
        
        printf("PI常量的值:%f",PI);
        
    }

    結果:

    原因:

    宏是預編譯中的一種情況(我在前面也有說到), 而預編譯主要就是替換,宏就是文本替換

    我們可以生成預編譯後的文件來查看:

    執行dos命令:

    打開文件預編譯後的文件macro.i文件:

    由於加載預編譯後的文本很長,這裡我主要顯示main主函數這部分:

    wint_t __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) fgetwchar (void);
     wint_t __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) fputwchar (wint_t);
     int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) getw (FILE*);
     int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) putw (int, FILE*);
    # 2 "macro.c" 2
    
    
    
    void main(){
    
     printf("PI常量的值:%f",3.1415);
    
    }

    我們可以看到原來的”PI”不見了,被替換成了3.1415

     

    2.帶參數的宏:

    源文件:C:\Users\Zero\Desktop\c\temp\macro2.c

    #include <stdio.h>
    
    #define AREA(x,y) x*y
    
    void main(){
        int a=6;
        int b=5;
        int result;
        
        result=AREA(a+b,a-b);
        
        printf("result:%d",result);
    }

    結果:

    原因:

    也許有人會認為”result=AREA(a+b,a-b)”的運算過程是這樣的:

    result = (a+b)*(a-b)    -->    result= (6+5)(6-5)  --> result=11

    不過,很遺憾它並不是函數,AREA(x,y) 不是函數 ,它不是函數!!!

    開始就說過,宏就是替換 ,追其本質, 這裡也是替換.

    查看預編譯後的文件:

    執行dos命令:

    打開文件預編譯後的文件macro2.i , 主要顯示main函數部分:

    wint_t __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) fgetwchar (void);
     wint_t __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) fputwchar (wint_t);
     int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) getw (FILE*);
     int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) putw (int, FILE*);
    # 2 "macro2.c" 2
    
    
    
    void main(){
     int a=6;
     int b=5;
     int result;
    
     result=a+b*a-b;
    
     printf("result:%d",result);
    }

    我們發現原來的”AREA(a+b,a-b)”被替換成了“a+b*a-b”

    result = (a+b)*(a-b)    -->    result= (6+5)(6-5)  --> result=11 

    result=a+b*a-b  –>  result=6+5*6-5  –>  result=31

    因為是替換,並不是函數,所以最後的結果是31

  •  

     

    關於宏的作用:

    1.可維護性

    源文件:C:\Users\Zero\Desktop\c\temp\effect.c

    #include <stdio.h>
    #define PI 3.14
    
    void main(){
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
    }

    比如:我們在控制台輸出10次PI的值, PI=3.14 , 後來,我發現3.14並不是我想要的結果,

    我想要修改原來3.14的值, 改成3.1415 ,這個時候 我只需要修改PI這個常量就可以了.並不需要修改10次

    #include <stdio.h>
    #define PI 3.1415
    
    void main(){
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
        printf("控制台輸出PI:%f\n",PI);
    }

    2.可讀性

    假如,一個常量為3.1415926, 你的代碼也很長的時候,去找3.1415926是非常麻煩的,

    #define PI=3.1415926  ,  你只需要找到PI就可以了

     

     

    結構體

    在實際問題中,一組數組往往具有不同的數據類型,這個時候就可以用到結構體

    結構體:結構體是基本數組類型組成,裡面可以存在不同類型的變量.像java中對象

    結構體定義的是一個類型, 就好像自己定義了整形(int)一樣

     

    結構體的定義:

    顯示聲明結構體:

    struct 結構體名{

    類型 變量名;

    類型 變量名;

    };

    匿名聲明結構體:

    struct {

    類型 變量名;

    類型 變量名;

    }結構體變量; 

     

    下面我將演示,及說明結構體的聲明:

    顯示聲明結構體:

    源文件:C:\Users\Zero\Desktop\c\temp\struct.c

    #include
     <stdio.h>
    #include <string.h> //導入strcpy()函數的頭文件   
    
    //顯示聲明結構體
    struct stu{
       char name[20];    //學生姓名
        int age;                //學生年齡
    };
    
    
    void main(){
        //聲明結構體變量    
        struct stu student;  //struct stu: 這裡是一個類型, student是一個變量
        
        //賦值 
        strcpy(student.name,"張二"); //student.name="張二",寫法是錯誤的
        //因為字符數組定義之後,是不能直接賦值的 ,不過,可以用strcpy()方法賦值  
        student.age=13;
        
        //控制台輸出
        printf("student.name:%s\n",student.name);
        printf("student.name:%d\n",student.age);        
    }

    編譯文件:

    兩者的定義都是差不多的。關於訪問結構體裡的變量 ,一般都是通過 “結構體變量.變量” 訪問

     

    匿名聲明結構體:

    源文件:C:\Users\Zero\Desktop\c\temp\struct2.c

    #include
     <stdio.h>
    #include <string.h> //導入strcpy()函數的頭文件
    
    //匿名聲明結構體
    struct{
        char name[20]; //學生姓名
        int age; //學生年齡
    }student;
    
    void main(){
        //賦值
        strcpy(student.name,"張三"); 
        student.age=23;
        
        //控制台輸出
        printf("student.name:%s\n",student.name);
        printf("student.age:%d\n",student.age);
    }

    編譯文件:

    原因是在匿名聲明結構體的時候,我就聲明了student變量, 創建匿名結構體的時候,是可以同時聲明變量的,因為它是匿名的, 匿名結構體通常只能用一次。

     

    typedef

    typedef, 我感覺還是挺好用的,typedefine的簡寫, 顧名思義就是類型定義,它可以給類型取一個別名.

    下面我們可以通過代碼來觀察:

  • 源文件:C:\Users\Zero\Desktop\c\temp\typedef.c

    #include
     <stdio.h>
    
    typedef int Integer;    //給int類型取個別名Integer
    typedef double Double; //給double類型取個別名Double
    
    
    void main(){
        Integer i=1;    //定義整形變量
        int j=10;  //定義整形變量
        Double mark=23.3;        //定義雙精度浮點變量
        
        printf("Integer i:%d\n",i);
        printf("int j:%d\n",j);
        printf("Double mark:%lf\n",mark);
    }

    即便是取了別名,原來的類型還是可以用的.

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    編譯文件:

typedef還可以用於結構體上:

源文件:C:\Users\Zero\Desktop\c\temp\typedef.c

顯示聲明:

#include
 <stdio.h>
#include <string.h> //導入strcpy函數的函數庫

//顯示定義學生結構體,別名stu_type
typedef struct stu{
    char name[20];//學生姓名
    int age;//學生年齡
}stu_type;

void main(){
    stu_type student; //聲明結構體變量student
    
    //賦值
    strcpy(student.name,"趙七");
    student.age=17;
    
    //控制台輸出
    printf("student.name:%s\n",student.name);
    printf("student.age:%d\n",student.age);
}

結果:

匿名聲明:

源文件:C:\Users\Zero\Desktop\c\temp\typedef3.c

#include <stdio.h>
#include <string.h> //導入strcpy函數的函數庫

//匿名定義學生結構體,別名stu_type
typedef struct{
    char name[20];//學生姓名
    int age;//學生年齡
}stu_type;

void main(){
    stu_type student; //聲明結構體變量student
    
    //賦值
    strcpy(student.name,"趙九");
    student.age=19;
    
    //控制台輸出
    printf("student.name:%s\n",student.name);
    printf("student.age:%d\n",student.age);
}

結果:

好了,文章到了這裡,也該結束了. 歡迎閱讀我學C的那些年

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved