Linux C语言结构体
前面學(xué)習(xí)了c語言的基本語法特性,本節(jié)進(jìn)行更深入的學(xué)習(xí)。
預(yù)處理程序。 編譯指令: 預(yù)處理, 宏定義,
建立自己的數(shù)據(jù)類型:結(jié)構(gòu)體,聯(lián)合體,動(dòng)態(tài)數(shù)據(jù)結(jié)構(gòu)
c語言表達(dá)式工具 邏輯運(yùn)算符:?& | ^ ~ << >>
函數(shù)的遞歸調(diào)用方法
什么是預(yù)處理
vim?helloworld.c1helloworld.c:
#include?int?main() {????printf("hello,world!\n");????return?0; }1234567編譯的目的:
從c語言.c源文件變成可執(zhí)行文件
gcc?helloworld.c?-o?helloworld.out./helloworld.out12編譯的四個(gè)步驟:
.c文件->.i文件->.s文件->.o文件->可執(zhí)行文件(可運(yùn)行)
下面我們來查看預(yù)處理中要做的事情:
gcc?-o?helloworld.i?helloworld.c?-E1-E表示只讓gcc執(zhí)行預(yù)處理。
//?查看helloworld.i文件cat?helloworld.i12vim跳到整個(gè)文檔底部,命令:?:$
可以看到代碼的底端是我們的main函數(shù)
對(duì)比一下.i文件和.c文件的區(qū)別
首先:它們都是c的語法。其次.c文件main函數(shù)上面是#include
而.i?文件中這行代碼不見了,變成了上面這些東西。
所以預(yù)處理所做的第一件事情就是展開頭文件
將#include 中stdio.h展開,將未注釋的內(nèi)容直接寫入.i文件。
在預(yù)處理步驟中,除了展開頭文件,還要進(jìn)行宏替換。
宏是什么
c語言常量分為直接常量和符號(hào)常量:
#define?標(biāo)識(shí)符?常量值?(注意:沒有分號(hào))1helloMacro.c源代碼:
#include?#define?R?10int?main() {????int?a?=R;????printf("a=%d\n");????printf("hello,world!\n");????return?0; }12345678910gcc?-o?helloMacro.i?helloMacro.c?-E1預(yù)處理過之后的代碼
#?4?"helloworld.c"int?main() {????int?a?=10;????printf("a=%d\n");????printf("hello,world!\n");????return?0; }12345678可以看到10是直接當(dāng)做一個(gè)字符串來替換原本的宏定義R。
宏的本質(zhì)是發(fā)生在預(yù)處理階段單純的字符串替換(宏替換), 在預(yù)處理階段,宏不考慮語法;
示例代碼2:
vim helloMacro2.c
預(yù)處理是沒有問題的,可以成功的編譯執(zhí)行。宏不考慮C語言的語法。它很單純,字符串替換。
宏用于大量反復(fù)使用的常量、數(shù)組buffer的大小,為了便于修改定義成宏。
通常定義數(shù)組我們這樣寫:
int?a[10];int?b[10];12定義兩個(gè)相同大小的數(shù)組,這里我們就可以改為下面代碼。
#define?R?10int?a[R];int?b[R];123一次修改,可以修改兩份。
宏也是可以傳遞參數(shù)的,可以做一些函數(shù)可以做的事情
宏函數(shù)
vim helloMacroFunction.c
源代碼:
這里的處理過程: 首先將參數(shù)a替換到上面的宏中,上面就變成了N(a) a*10,之后再用a*10替換下面的N(a)
int?b?=?N(a);?//變成了?int?b?=a*10;1gcc?-o?helloMacroFunction.i?helloMacroFunction.c?-E1預(yù)處理之后:
#?8?"hello.c"int?main(){????int?a?=?10;????int?b?=a*10;????printf("b?=?%d\n",b);????printf("a?=%d\n",a);????printf("hello,world!\n");????return?0; }123456789先不考慮宏實(shí)現(xiàn),先來寫一個(gè)正常的求和函數(shù)。
vim?helloAdd.c1#include?#define?R?20#define?M?int?main(#define?N(n)?n*10int?add(int?a,int?b){????return?a b; }M){????int?a?=?R;????printf("a?=%d\n",a);????printf("hello,world!\n");????int?b?=N(a);????printf("b?=?%d\n",b);????int?c?=add(a,b);????printf("c?=%d\n",c);????return?0; }1234567891011121314151617181920212223gcc?helloAdd.c?-o?helloAdd.out./helloAdd.out12使用宏函數(shù)實(shí)現(xiàn)求和。
vim?helloAddMacro.c1#include?#define?R?20#define?M?int?main(#define?N(n)?n*10#define?ADD(a,b)?a bint?add(int?a,int?b){????return?a b; }M){????int?a?=?R;????printf("a?=%d\n",a);????printf("hello,world!\n");????int?b?=N(a);????printf("b?=?%d\n",b);????int?c?=add(a,b);????printf("c?=%d\n",c);????int?d?=ADD(a,b);????printf("d?=%d\n",d);????return?0; }1234567891011121314151617181920212223242526gcc?helloAddMacro.c?-o?helloAddMacro.out./helloAddMacro.out12可以看到使用宏函數(shù)和普通函數(shù)的求和效果是一致的。結(jié)果與簡(jiǎn)單的字符串替換一致。
ADD(a,b)?被替換成?a b?因此式子變成int d = a b;
gcc?-o?helloAddMacro.i?helloAddMacro.c?-E vim?helloAddMacro.i12版本3,宏定義中優(yōu)先級(jí)問題。
#include?#define?R?20#define?M?int?main(#define?N(n)?n*10#define?ADD(a,b)?a bint?add(int?a,int?b){????return?a b; }M){????int?a?=?R;????printf("a?=%d\n",a);????printf("hello,world!\n");????int?b?=N(a);????printf("b?=?%d\n",b);????int?c?=add(a,b);????printf("c?=%d\n",c);????int?d?=ADD(a,b);????printf("d?=%d\n",d);????int?e?=ADD(a,b)?*?ADD(a,b);????printf("e?=%d\n",e);????return?0; }1234567891011121314151617181920212223242526272829預(yù)測(cè)一下e的輸出為:?a b*a b?ab先乘起來,a=20,b=200,ab=4000,然后加上a,b:得到結(jié)果(4220)
gcc?helloAddMacroPrecedence.c?-o?helloAddMacroPrecedence.out./helloAddMacroPrecedence.out12運(yùn)算是等我們編譯完了,執(zhí)行的時(shí)候才會(huì)運(yùn)行的。預(yù)處理階段不會(huì)進(jìn)行運(yùn)算操作。
宏定義時(shí)由于本質(zhì)是字符串的替換
真正運(yùn)算的時(shí)候,會(huì)按照運(yùn)算符號(hào)的優(yōu)先級(jí)來進(jìn)行
解決方案:
#define?ADD(a,b)?(a b)1gcc?helloAddMacroPrecedence.c?-o?helloAddMacroPrecedence2.out./helloAddMacroPrecedence2.out12加個(gè)括號(hào),保證優(yōu)先級(jí)更高一點(diǎn)。
宏函數(shù)和正常函數(shù)的優(yōu)勢(shì)?
正常的add函數(shù)需要返回值類型,需要傳遞進(jìn)來的參數(shù)有類型要求。
講傳入的a,b 類型進(jìn)行改變,如變?yōu)閮蓚€(gè)浮點(diǎn)型數(shù),程序就會(huì)自動(dòng)類型轉(zhuǎn)換。
但是宏函數(shù)就沒有這種要求可以不用考慮輸入值的類型,這與普通的函數(shù)定義不同。
int?c?=add(10.5,20.4);printf("c?=%d\n",c);float?d?=ADD(10.5,20.4);printf("d?=%f\n",d);12345gcc?helloAddMacroPrecedenceCompare.c?-o?helloAddMacroPrecedenceCompare.out./helloAddMacroPrecedenceCompare.out12普通函數(shù)例如int add(int a,int b)除了在開頭要聲明值的類型,還要設(shè)置返回值,因此在定義過程與調(diào)用過程相對(duì)復(fù)雜。若能用宏定義實(shí)現(xiàn)的情況應(yīng)優(yōu)先考慮宏定義.
宏是不考慮數(shù)據(jù)類型,不考慮c語言的語法的。只是簡(jiǎn)單的字符串的處理。
預(yù)處理階段,除了宏之外,還提供了一個(gè)叫做mtianyan:條件編譯的功能。
可以按照不同的條件,編譯不同的程序部分,從而產(chǎn)生不同的目標(biāo)代碼文件。對(duì)于程序的移植和調(diào)試都是很有用的。
下集預(yù)告: 和宏比較相近的功能,typedef
Linux C預(yù)處理之typedef
嚴(yán)格來講,typedef和預(yù)處理是沒
總結(jié)
以上是生活随笔為你收集整理的Linux C语言结构体的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 半智能手机是什么意思
- 下一篇: Linux C语言编程基本原理与实践