日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux C语言结构体

發布時間:2023/12/2 linux 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux C语言结构体 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面學習了c語言的基本語法特性,本節進行更深入的學習。

  • 預處理程序。 編譯指令: 預處理, 宏定義,

  • 建立自己的數據類型:結構體,聯合體,動態數據結構

  • c語言表達式工具 邏輯運算符:?& | ^ ~ << >>

  • 函數的遞歸調用方法


什么是預處理

vim?helloworld.c1

helloworld.c:

#include?int?main() {????printf("hello,world!\n");????return?0; }1234567

編譯的目的:

從c語言.c源文件變成可執行文件

gcc?helloworld.c?-o?helloworld.out./helloworld.out12

編譯的四個步驟:

.c文件->.i文件->.s文件->.o文件->可執行文件(可運行)

下面我們來查看預處理中要做的事情:

gcc?-o?helloworld.i?helloworld.c?-E1

-E表示只讓gcc執行預處理。

//?查看helloworld.i文件cat?helloworld.i12

vim跳到整個文檔底部,命令:?:$

可以看到代碼的底端是我們的main函數

對比一下.i文件和.c文件的區別

首先:它們都是c的語法。其次.c文件main函數上面是#include

而.i?文件中這行代碼不見了,變成了上面這些東西。

所以預處理所做的第一件事情就是展開頭文件

將#include 中stdio.h展開,將未注釋的內容直接寫入.i文件。

在預處理步驟中,除了展開頭文件,還要進行宏替換。


宏是什么

c語言常量分為直接常量和符號常量:

#define?標識符?常量值?(注意:沒有分號)1

helloMacro.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

預處理過之后的代碼

#?4?"helloworld.c"int?main() {????int?a?=10;????printf("a=%d\n");????printf("hello,world!\n");????return?0; }12345678

可以看到10是直接當做一個字符串來替換原本的宏定義R。

宏的本質是發生在預處理階段單純的字符串替換(宏替換), 在預處理階段,宏不考慮語法;

示例代碼2:
vim helloMacro2.c

#include?#define?R?10#define?M?int?main(M){????printf("hello,world!\n");????return?0; }12345678gcc?helloMacro2.c?-o?helloMacro2.out./helloMacro2.out12

預處理是沒有問題的,可以成功的編譯執行。宏不考慮C語言的語法。它很單純,字符串替換。

  • 宏用于大量反復使用的常量、數組buffer的大小,為了便于修改定義成宏。

通常定義數組我們這樣寫:

int?a[10];int?b[10];12

定義兩個相同大小的數組,這里我們就可以改為下面代碼。

#define?R?10int?a[R];int?b[R];123

一次修改,可以修改兩份。

宏也是可以傳遞參數的,可以做一些函數可以做的事情

宏函數

vim helloMacroFunction.c
源代碼:

#include?#define?R?10#define?M?int?main(#define?N(n)?n*10M){????int?a?=?R;????int?b?=?N(a);????printf("b?=?%d\n",b);????printf("a?=%d\n",a);????printf("hello,world!\n");????return?0; }123456789101112131415gcc?helloMacroFunction.c?-o?helloMacroFunction.out./helloMacroFunction.out12

這里的處理過程: 首先將參數a替換到上面的宏中,上面就變成了N(a) a*10,之后再用a*10替換下面的N(a)

int?b?=?N(a);?//變成了?int?b?=a*10;1gcc?-o?helloMacroFunction.i?helloMacroFunction.c?-E1

預處理之后:

#?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

先不考慮宏實現,先來寫一個正常的求和函數。

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

使用宏函數實現求和。

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

可以看到使用宏函數和普通函數的求和效果是一致的。結果與簡單的字符串替換一致。

ADD(a,b)?被替換成?a b?因此式子變成int d = a b;

gcc?-o?helloAddMacro.i?helloAddMacro.c?-E vim?helloAddMacro.i12

版本3,宏定義中優先級問題。

#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

預測一下e的輸出為:?a b*a b?ab先乘起來,a=20,b=200,ab=4000,然后加上a,b:得到結果(4220)

gcc?helloAddMacroPrecedence.c?-o?helloAddMacroPrecedence.out./helloAddMacroPrecedence.out12

運算是等我們編譯完了,執行的時候才會運行的。預處理階段不會進行運算操作。

  • 宏定義時由于本質是字符串的替換

真正運算的時候,會按照運算符號的優先級來進行

解決方案:

#define?ADD(a,b)?(a b)1gcc?helloAddMacroPrecedence.c?-o?helloAddMacroPrecedence2.out./helloAddMacroPrecedence2.out12

加個括號,保證優先級更高一點。

宏函數和正常函數的優勢?

正常的add函數需要返回值類型,需要傳遞進來的參數有類型要求。

講傳入的a,b 類型進行改變,如變為兩個浮點型數,程序就會自動類型轉換。

但是宏函數就沒有這種要求可以不用考慮輸入值的類型,這與普通的函數定義不同。

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

普通函數例如int add(int a,int b)除了在開頭要聲明值的類型,還要設置返回值,因此在定義過程與調用過程相對復雜。若能用宏定義實現的情況應優先考慮宏定義.

宏是不考慮數據類型,不考慮c語言的語法的。只是簡單的字符串的處理。

預處理階段,除了宏之外,還提供了一個叫做mtianyan:條件編譯的功能。

可以按照不同的條件,編譯不同的程序部分,從而產生不同的目標代碼文件。對于程序的移植和調試都是很有用的。

下集預告: 和宏比較相近的功能,typedef


Linux C預處理之typedef

嚴格來講,typedef和預處理是沒

總結

以上是生活随笔為你收集整理的Linux C语言结构体的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。