91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

關于C語言進階的操作

Q4MP_gh_c472c21 ? 來源:嵌入式ARM ? 作者:嵌入式ARM ? 2020-10-10 11:27 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

1、操作一波 咱們先體驗一波#include“xxx.c”文件能不能用:

參考demo:

1//FileName :main 2#include 《stdio.h》 3#include 《stdlib.h》 4 5/*************************** 6 * .c文件聲明區(qū)域 7 **************************/ 8#include“module1.c” 9#include“module2.c” 10 11/*************************** 12 * Fuction: main 13 * Author :(最后一個bug) 14 **************************/ 15int main(int argc, char *argv[]) { 16 17 Fuction1(); 18 Fuction2(); 19 printf(“歡迎關注公眾號:最后一個bug ”); 20 return 0; 21}

1//FileName: Module1.c 2#include《stdio.h》 3/*************************** 4 * Fuction: Fuction1 5 * Author :(最后一個bug) 6 **************************/ 7void Fuction1() 8{ 9 printf(“Run Fuction1 ”); 10}

1//FileName: Module2.c 2#include《stdio.h》 3/*************************** 4 * Fuction: Fuction2 5 * Author :(最后一個bug) 6 **************************/ 7void Fuction2() 8{ 9 printf(“Run Fuction2 ”); 10}

輸出結果:

分析一下:

看來這波操作可行,似乎還省去了.h文件,之前bug菌說過,分析.h文件的時候直接把.h文件在對應的.c文件中的位置處展開然后進一步分析即可,其實這.c文件也是如此,接著往下看。

參考demo:

1//FileName :main 2#include 《stdio.h》 3#include 《stdlib.h》 4 5char * cBug1 = “bugNo1”; //這里是位置1 6char * cBug2 = “bugNo2”; 7/*************************** 8 * .c文件聲明區(qū)域 9 **************************/ 10#include“module1.c” 11#include“module2.c” 12 13//char * cBug1 = “bugNo1”;//這里是位置2 14//char * cBug2 = “bugNo2”; 15 16/*************************** 17 * Fuction: main 18 * Author :(最后一個bug) 19 **************************/ 20int main(int argc, char *argv[]) { 21 22 Fuction1(); 23 Fuction2(); 24 printf(“歡迎關注公眾號:最后一個bug ”); 25 return 0; 26}

1//FileName: Module2.c 2#include《stdio.h》 3/*************************** 4 * Fuction: Fuction1 5 * Author :(最后一個bug) 6 **************************/ 7void Fuction1() 8{ 9 printf(“Run Fuction1 ”); 10 printf(“%s ”,cBug1); 11}

1//FileName: Module2.c 2#include《stdio.h》 3/*************************** 4 * Fuction: Fuction2 5 * Author :(最后一個bug) 6 **************************/ 7void Fuction2() 8{ 9 printf(“Run Fuction2 ”); 10 printf(“%s ”,cBug2); 11}

輸出結果:

分析一下:

我們在位置1進行兩個變量的定義,成功編譯運行得到如上的結果,符合我們的預期,然而當我們去掉位置1進行位置2的定義,程序卻無法進行編譯,看來跟我們預期在編譯過程中直接展開.c文件是一致的。

2、有什么用? 這種方式在bug菌的編碼歷史長河中一般只在兩種情況下用到:

1、維護毫無設計的代碼

有些歷史悠久的項目經過了N多位大佬的蹂躪,說實在的代碼結構上已經非??膳铝?,往往每個源文件內容非常之長,為了保持代碼原樣,會采用#include“xxx.c”把這幾的相關文件嵌入進去,也便于自己后期維護。

2、測試代碼

在前期進行軟件調試的時候可能自己會在不同的文件中安插不同測試功能函數,通過這樣方法可以方便的引入和剔除。

比如說你需要對源文件中的一些靜態(tài)變量進行相關的監(jiān)控處理,然而又不想在本文件中增加測試代碼,于是便可以在#include“xxx.c”中進行測試函數的編寫來供使用,比如 :

1//FileName :main 2#include 《stdio.h》 3#include 《stdlib.h》 4 5static int a = 5; 6/*************************** 7 * .c文件聲明區(qū)域 8 **************************/ 9#include“module1.c” 10 11/*************************** 12 * Fuction: main 13 * Author :(最后一個bug) 14 **************************/ 15int main(int argc, char *argv[]) { 16 17 Fuction1(); 18 printf(“main %d ”,a); 19 printf(“歡迎關注公眾號:最后一個bug ”); 20 return 0; 21}

1//FileName: Module2.c 2#include《stdio.h》 3/*************************** 4 * Fuction: Fuction1 5 * Author :(最后一個bug) 6 **************************/ 7void Fuction1() 8{ 9 printf(“Run Fuction1 ”); 10 printf(“Fuction1 %d ”,a); 11}

注意了!!

那么之前有小伙伴說 : “ static的作用域僅僅在對應的文件中 ”,通過上面的多個.c文件使用靜態(tài)a變量,那么這位小伙伴表述就不那么貼切了! 3、技術總結 大家在正常的開發(fā)過程中bug菌還是不建議使用#include“xxx.c”,因為在我們程序的設計過程中,.h文件就是一種外部的引用接口,而.c是對應的內部實現,如果濫用#include“xxx.c”有可能造成函數等等的重復定義,同時也對調試相關程序帶來一些困擾,當然如果游刃有余就沒啥問題的啦。 不過對于喜歡寫長文件的小伙伴來說卻是是福音,把一個長的.c文件分成多個.c文件,這樣至少可以把不知道這種用法的同事面前秀一秀!

void

1、簡單認識一下void void在大部分小伙伴的程序中都只是用于函數無參數傳入,或者無類型返回。然而我們平時所定義的變量都會有具體的類型,int,float,char等等,那是否有void類型的變量呢?大家可以動手實驗一下,答案是:不行,編譯會出錯。

上圖很明顯編譯器不允許定義void類型的變量,變量都是需要占用一定內存的,既然void表示無類型,編譯器自然也就不知道該為其分配多大的內存,于是造成編譯失敗。 雖然void不能直接修飾變量,但是其可以用于修飾指針的指向即無類型指針void*,無類型指針那就有意義了,無類型指針不是一定要指向無類型數據,而是可以指向任意類型的數據。 2、void * 基本操作 大家其實在使用動態(tài)內存分配的使用就已經遇到了void *的使用,來我們一起看看如下幾個標準函數的原型定義:

上面這些函數都是與內存操作有關的函數,可能一些小伙伴使用過也不一定知道每個參數的具體類型是什么,這些void*部分的形參所傳入的實參都是不需要進行強制類型轉化的,所以根本就不需要關注傳入指針所指向的具體類型,然而函數所返回的void *一般都需要通過強制類型轉化為對應的具體類型,除非你最后所傳遞的變量也是void*類型。

參考void*用法:

1#include 《stdio.h》 2#include 《stdlib.h》 3#include 《malloc.h》 4 5#define NUM 10 6/************************************* 7 * Fuction:了解一下void*的使用 8 * Author : (最后一個bug) 9 *************************************/ 10int main(int argc, char *argv[]) { 11 int *p1 = (int *)malloc(NUM*sizeof(int)); 12 int *p2 = (int *)malloc(NUM*sizeof(int)); 13 int i = 0; 14 15 //初始化p1 16 for(i = 0;i 《 NUM;i++) 17 { 18 *(p1+i) = i; 19 } 20 //進行內存copy 21 memcpy(p2,p1,NUM*sizeof(int)); 22 23 //輸出另外一個分配的內存 24 for(i = 0;i 《 NUM;i++) 25 { 26 printf(“%d,”,*(p2+i)); 27 } 28 //釋放內存 29 free(p1); 30 free(p2); 31 return 0; 32}

運行結果:

3、使用void * 實現無類型數據封裝 為了保持文章的完整性,也許這里才是作者最想跟大家介紹的,void*既然如此的靈活一定大有用處,如果僅僅只是用來簡單的傳遞參數似乎有點大材小用,我們得把其用到上層的軟件設計上來。 在一些項目中經??吹接行』锇榘褦祿愋娃D來轉去,甚至有時候為了一個數據類型的變化還得重新寫一個僅僅數據類型不同的函數,這樣的代碼上萬行代碼指日可待,按下面我們以一個例子來跟大家介紹一種辦法能夠減少數據類型變化所帶來的程序重復代碼的增加。

參考實例:

1#include 《stdio.h》 2#include 《stdlib.h》 3/********************************** 4 * Fuction : add 5 * descir : 加法的相關數據及處理辦法 6 * Author : (最后一個bug) 7 **********************************/ 8typedef struct _tag_Add 9{ 10 int a; 11 int b; 12 int result; 13}sAdd; 14 15void Add(void *param) 16{ 17 sAdd *p = (sAdd *) param; 18 p-》result = p-》a + p-》b; 19} 20/********************************** 21 * Fuction : add 22 * descir : 乘法的相關數據及處理辦法 23 * Author : (最后一個bug) 24 **********************************/ 25typedef struct _tag_Mul 26{ 27 float a; 28 float b; 29 float result; 30}sMul; 31 32void Mul(void *param) 33{ 34 sMul *p = (sMul *) param; 35 p-》result = p-》a * p-》b; 36} 37 38/************************************* 39 * Fuction : sCal 40 * descir : 公共的調用接口 41 * Author : (最后一個bug) 42 ************************************/ 43void sCal(void *param,void *fuc) 44{ 45 ((void (*)(void*))fuc)(param); 46} 47 48/********************************** 49 * Fuction : main 50 * descir : 應用接口實例 51 * Author : (最后一個bug) 52 **********************************/ 53int main(void) 54{ 55 sAdd stAdd; 56 sMul stMul; 57 58 //數據初始化 59 stAdd.a = 10; 60 stAdd.b = 20; 61 62 stMul.a = 5; 63 stMul.b = 5; 64 //接口直接用 65 sCal(&stAdd,Add); 66 sCal(&stMul,Mul); 67 //對應的輸出 68 printf(“a + b = %d ”,stAdd.result); 69 printf(“a * b = %f ”,stMul.result); 70 printf(“公眾號:最后一個bug ”); 71 return 0; 72 }

運行結果:

分析一下:

上面的例子可能還是無法完全彰顯void*的強悍之處了,不過其主要的作用就是為了隱藏數據類型,大家也可以理解為一種數據類型的抽象處理,這也是面向對象編程的一種體現。 4、技術總結 大家一定要記得對于一些編程技巧一定要嘗試著去使用,可能達到項目目標的方式有很多種,但是一些好的設計不僅僅會讓你的代碼增色不少,同時也會讓同事們覺得你是一個喜歡專研技術的人。

“ 逗號表達式 ”

1、先來一個逗號表達式例子

一個逗號表達式的實例:

1#include 《stdio.h》 2#include 《stdlib.h》 3/****************************************** 4 * Fuction: Main 5 * Descir : 測試一個逗號表達式 6 * Author :(最后一個bug) 7 *****************************************/ 8int main(int argc, char *argv[]) { 9 int Val = 1; 10 11 Val = ++Val,Val+10,Val*10; //逗號表達式 12 13 printf(“Val = %d”,Val); 14 15 return 0; 16}

分析一下:

大家首先可以自己算一下最后輸出的結果,然后再去看下面的答案,其實對于逗號表達式的語法規(guī)則并不是很難,主要是大家在平時的開發(fā)中使用得比較少,一旦經常不使用就容易淡忘。

逗號表達式的形式 : 表達式1,表達式2,。..。..,表達式n

三點搞定:

逗號表達式從表達式1開始順序從左向右執(zhí)行;

其逗號表達式最后的值為最后一個表達式的值;

逗號運算的優(yōu)先級最低,也就說明與其他運算符結合使用的時候,在沒有括號的情況下逗號運算符最后才執(zhí)行。

上面例子的結果:

可能有部分小伙伴算出的結果是10,主要是沒有考慮其逗號表達式優(yōu)先級最低,所以第一賦值表達式優(yōu)先執(zhí)行。 2、“不怎么用”是不是就“沒有用”? 既然大家平時都用得不多,是不是這個逗號表達式就是多此一舉呢 ? C發(fā)展這么多年,如果真的沒有價值估計早就不存在了吧,所以還是要秉承著“存在即是合理”的態(tài)度看待逗號表達式。

大家在平時閱讀代碼的時候應該都是按照從左至右,然后從上至下來的方式吧?;旧弦粋€分號結束一行的書寫,由于電腦屏幕的限制,有效代碼暴露在人的視野中是有限的,同時人瞬間記憶時間也是有限的,如果在一個小小的屏幕上閱碼勢必會阻礙程序員的閱讀和理解,比如下面兩種書寫方式:

1/****************************************** 2 * Fuction: 非逗號表達式書寫 3 * Descir : 4 * Author :(最后一個bug) 5 *****************************************/ 6if(IsOk()) 7{ 8 sOkProc(); 9 return GetOkCode(); 10} 11else 12{ 13 sNoProc(); 14 return GetNoCode(); 15} 16/****************************************** 17 * Fuction: 采用逗號表達式書寫 18 * Descir : 19 * Author :(最后一個bug) 20 *****************************************/ 21return (IsOk())?(sOkProc(),GetOkCode()):(sNoProc(),GetNoCode());

分析一下:

上面是兩種代碼書寫方式,第一種占據了多行,而第二種進占據一行,這樣同樣一個屏幕所容納的有效代碼第一種就明顯少于第二種方式,所以很多程序員都會選擇使用一種大長屏或者多屏進行開發(fā)。

第二種方式似乎很多小伙伴覺得代碼不夠美觀,也不便于維護,其實這僅僅只是一種習慣罷了,就好像編碼的時候 : 第一個大括號是否需要另外起一行,或者是使用==號一定要像if( 1== b)這樣把數據放左邊,當你習慣了這種編碼風格也會覺得用第二方式來得直接。

3、逗號表達式常用的地方

下面為大家介紹幾個用逗號表示式比較多的地方:

1、for循環(huán)中的處理

參考demo:

1#include 《stdio.h》 2#include 《stdlib.h》 3#define ROW_NUM (5) 4#define LINE_NUM (5) 5/****************************************** 6 * Fuction: Main 7 * Descir :for 遍歷查找 8 * Author :(最后一個bug) 9 *****************************************/ 10int main(int argc, char *argv[]) { 11 int i = 0,j = 0; 12 int Matrix[ROW_NUM][LINE_NUM] ={{1,1,1,1,1}, 13 {2,2,2,2,2}, 14 {3,3,3,3,3}, 15 {4,4,4,4,4}, 16 {5,5,5,5,5}, 17 }; 18 19 for(i = 0,j = 0;(i 《 ROW_NUM)&&(j 《 LINE_NUM);i++,j += 2) 20 { 21 printf(“Matrix[%d][%d] = %d ”,i,j,Matrix[i][j]); 22 } 23 printf(“公眾號:最后一個bug ”); 24 return 0; 25}

分析一下:

上面在for循環(huán)中遍歷相關數據幾比較常規(guī)的處理,也是逗號表達式經常出現的地方,這樣的表現形式讓代碼更加簡單明了。

其結果如下:

2、弱化++處理大家應該都知道++在前先執(zhí)行自加,然后再進行相應處理,而++在后則相反,那么我們可以使用逗號運算符優(yōu)先級最低的特點來弱化該問題,避免編碼出現bug。

參考Demo

1#include 《stdio.h》 2#include 《stdlib.h》 3/****************************************** 4 * Fuction: Main 5 * Descir :弱化++前后問題 6 * Author :(最后一個bug) 7 *****************************************/ 8int main(int argc, char *argv[]) { 9 int i = 0; 10 11 //1、常規(guī)操作 12 i = 0; 13 while(++i 《 3) 14 { 15 printf(“ i = %d ”,i); 16 } 17 printf(“***************** ”); 18 19 i = 0; 20 while(i++ 《 3) 21 { 22 printf(“ i = %d ”,i); 23 } 24 printf(“*****************n”); 25 26 //2、逗號表達式處理一下 27 i = 0; 28 while( i++,i 《 3) 29 { 30 printf(“ i = %d ”,i); 31 } 32 printf(“*****************n”); 33 34 i = 0; 35 while( ++i,i 《 3) 36 { 37 printf(“ i = %d ”,i); 38 } 39 printf(“*****************n”); 40 41 printf(“公眾號:最后一個bugn”); 42 return 0; 43} 44

分析一下:

當使用逗號表達式以后,不管++在前還是在后,其都會自增加1,然后再進行右邊表達式的處理,這樣就不用擔心是不是多記了一次,導致各種問題。

運行結果:

3、更加精簡宏定義

參考demo

1#include 《stdio.h》 2#include 《stdlib.h》 3 4#define GET_INDEX(a ,b) ( a+= 2,a + b) 5/****************************************** 6 * Fuction: Main 7 * Descir : 簡化宏 8 * Author :(最后一個bug) 9 *****************************************/ 10int main(int argc, char *argv[]) { 11 int i = 0,Val = 0; 12 int Param1 = 0, Param2 = 0; 13 int Matrix[5] ={5,5,5,5,5}; 14 15 printf(“ Matrix = %d ”,Matrix[GET_INDEX(Param1,Param2)]); 16 printf(“公眾號:最后一個bug ”); 17 return 0; 18}

分析一下:

逗號表達式最終還是一個表達式,所以它可以直接用在幾乎所有變量可以用的地方,這是和語句不同的。

所以逗號表達式左邊的表達式可以預先進行各種處理,其最右邊的表達式相當于返回最后的結果,從而減少函數的封裝和調用。

4、技術總結

逗號表達式其實就是橫向編碼的一種方式,能夠讓程序員更好的利用一行的空間,使得代碼更加緊湊,所以使用逗號表達式并沒炫技,而是增強了代碼的靈活度,不過話說回來逗號表達式在C混亂編碼大賽上的使用頻度是非常之高的。

責任編輯:YYX

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯系本站處理。 舉報投訴
  • C語言
    +關注

    關注

    183

    文章

    7644

    瀏覽量

    145588
  • 代碼
    +關注

    關注

    30

    文章

    4968

    瀏覽量

    73965
  • 編譯器
    +關注

    關注

    1

    文章

    1672

    瀏覽量

    51602

原文標題:C語言進階技術:同事這些操作把我驚呆了!

文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    C語言重點—指針篇

    C語言是比較偏底層的語言,為什么他比較偏底層,就是因為他的很多操作都是直接針對內存操作的。 這篇我們就來講解
    發(fā)表于 01-22 08:23

    C語言主要特點

    。 5.語法限制不太嚴格,程序設計自由度大。 6.C語言允許直接訪問物理地址,能進行位(bit)操作,能夠實現匯編語言的大部分功能,可以直接對硬件進行
    發(fā)表于 01-05 07:41

    C語言嵌入式系統(tǒng)編程注意事項-內存操作

    C語言嵌入式系統(tǒng)編程注意事項之內存操作 在嵌入式系統(tǒng)的編程中,常常要求在特定的內存單元讀寫內容,匯編有對應的MOV指令,而除C/C++以外的
    發(fā)表于 01-04 07:31

    C語言C++的區(qū)別及聯系

    C語言C++到底是什么關系? 首先C++和C語言本來就是兩種不同的編程
    發(fā)表于 12-24 07:23

    C語言C++之間的區(qū)別是什么

    區(qū)別 1、面向對象編程 (OOP): C語言是一種面向過程的語言,它強調的是通過函數將任務分解為一系列步驟進行執(zhí)行。 C++在C
    發(fā)表于 12-11 06:23

    C語言特性

    1、高效性:直接操作硬件 C 語言代碼的執(zhí)行效率極高,這是其最為顯著的優(yōu)勢之一。它能夠直接訪問硬件資源,與底層硬件進行緊密交互,充分發(fā)揮硬件的性能潛力。在嵌入式開發(fā)中,硬件資源往往十分有限,對程序
    發(fā)表于 11-24 07:01

    C語言操作

    C 語言操作符包括按位與( )、按位或(|)、按位異或(^)、按位取反(~)、左移(<<)和右移(>>)。 按位與( ) 只有當兩個二進制位
    發(fā)表于 11-21 07:52

    漢諾塔C語言的遞歸操作

    漢諾塔:請輸入盤子數,輸出盤子移動的操作步驟。 #include void move(char from, char to) { printf(\"%c to %cn\"
    發(fā)表于 11-17 07:59

    C語言和單片機C語言有什么差異

    語言的功能特性外,它可以很好的操作底層的硬件接口。在C語言的基礎上,如果你把一些單片機的端口或特殊功能寄存器加于定義,使用的時候會更加方便,寫語句的時候,直接直觀的編寫。這樣就差不多是
    發(fā)表于 11-14 07:55

    C語言的printf基本用法介紹

    個小數。f 是 float 的簡寫。 除了這些,printf 支持更加復雜和優(yōu)美的輸出格式,考慮到讀者的基礎暫時不夠,我們將在《C語言數據輸出大匯總以及輕量進階》一節(jié)中展開講解。 我們把代碼補充完整
    發(fā)表于 11-12 07:04

    嵌入式從入門到進階,怎么學?

    嵌入式從入門到進階,怎么學? 嵌入式學習的核心是 “軟硬結合的技術壁壘”,科學分層才能高效突破。以下是從入門到高階的精簡路線,幫你避開彎路: 1、基礎奠基層:構建技術底座 C 語言聚焦 指針、結構體
    發(fā)表于 09-02 09:44

    RK3568驅動指南|驅動基礎進階篇-進階7 向系統(tǒng)中添加一個系統(tǒng)調用

    RK3568驅動指南|驅動基礎進階篇-進階7 向系統(tǒng)中添加一個系統(tǒng)調用
    的頭像 發(fā)表于 05-21 14:15 ?711次閱讀
    RK3568驅動指南|驅動基礎<b class='flag-5'>進階</b>篇-<b class='flag-5'>進階</b>7 向系統(tǒng)中添加一個系統(tǒng)調用

    深入理解C語言C語言循環(huán)控制

    C語言編程中,循環(huán)結構是至關重要的,它可以讓程序重復執(zhí)行特定的代碼塊,從而提高編程效率。然而,為了避免程序進入無限循環(huán),C語言提供了多種循環(huán)控制語句,如break、continue和
    的頭像 發(fā)表于 04-29 18:49 ?2046次閱讀
    深入理解<b class='flag-5'>C</b><b class='flag-5'>語言</b>:<b class='flag-5'>C</b><b class='flag-5'>語言</b>循環(huán)控制

    C語言的歷史及程序介紹

    電子發(fā)燒友網站提供《C語言的歷史及程序介紹.pdf》資料免費下載
    發(fā)表于 04-09 16:10 ?0次下載

    為什么學了C語言,卻寫不出像樣的項目?

    在學習編程的路上,C語言幾乎是每個程序員的“必修課”。不管你是打算從事嵌入式開發(fā)、系統(tǒng)編程,還是想要深入理解操作系統(tǒng)的底層原理,C語言都是一
    的頭像 發(fā)表于 03-14 17:37 ?918次閱讀
    為什么學了<b class='flag-5'>C</b><b class='flag-5'>語言</b>,卻寫不出像樣的項目?