基于c语言的linux嵌入式开发入门
前言
本文主要包含,c語言基本結構與語法、make及makefile的使用、main函數參數與返回值的說明、標準輸入、輸出、錯誤流的介紹以及linux管道的應用。
語言數據類型
聯合體也有翻譯為共用體的,結構類型,也有翻譯為結構體的,僅僅是翻譯問題,類型是一樣的
每個變量都會占用一定的存儲單元。
符號常量
100 // 直接常量 "Hello"#define PI 3.14 //符號常量自動類型轉換
強制類型轉換
在使用強制轉換時應注意以下問題:
1、數據類型和表達式都必須加括號,如把(int)(x/2+y)寫成(int)x/2+y則成了把x轉換成int型之后再除2再與y相加了。
2、轉換后不會改變原數據的類型及變量值,只在本次運算中臨時性轉換。
3、強制轉換后的運算結果不遵循四舍五入原則。
計算順序
int a = 3; b = 4;計算a+b%(a+b)/a+a*b-b該算式的運算結果
計算順序
1、a+b
2、b%(a+b)/a和ab
3、a+b%(a+b)/a+ab-b
小的數字mod 大的數字,余數還是其本身。
運算符優先級
爆破彗星是個什么樣的游戲?
C語言變量存儲類別
C語言根據變量的生存周期來劃分,可以分為靜態存儲方式和動態存儲方式。
靜態存儲方式:是指在程序運行期間分配固定的存儲空間的方式。靜態存儲區中存放了在整個程序執行過程中都存在的變量,如全局變量。
動態存儲方式:是指在程序運行期間根據需要進行動態的分配存儲空間的方式。動態存儲區中存放的變量是根據程序運行的需要而建立和釋放的,通常包括:函數形式參數;自動變量;函數調用時的現場保護和返回地址等。
C語言中存儲類別又分為四類:自動(auto)、靜態(static)、寄存器的(register)和外部的(extern)。
1、用關鍵字auto定義的變量為自動變量,auto可以省略,auto不寫則隱含定為“自動存儲類別”,屬于動態存儲方式。
2、用static修飾的為靜態變量,如果定義在函數內部的,稱之為靜態局部變量;如果定義在函數外部,稱之為靜態外部變量。函數的形式參數不可以說明為satic類型。
注意:靜態局部變量屬于靜態存儲類別,在靜態存儲區內分配存儲單元,在程序整個運行期間都不釋放;靜態局部變量在編譯時賦初值,即只賦初值一次;如果在定義局部變量時不賦初值的話,則對靜態局部變量來說,編譯時自動賦初值0(對數值型變量)或空字符(對字符變量)。
3、為了提高效率,C語言允許將局部變量得值放在CPU中的寄存器中,這種變量叫“寄存器變量”,用關鍵字register作聲明。
注意:只有局部自動變量和形式參數可以作為寄存器變量;一個計算機系統中的寄存器數目有限,不能定義任意多個寄存器變量;局部靜態變量不能定義為寄存器變量。
4、用extern聲明的的變量是外部變量,外部變量的意義是某函數可以調用在該函數之后定義的變量。
#include <stdio.h> void fn() {static int x = 1; //定義靜態局部變量x*=2;printf("x=%d\n",x); }int main() {int i;for(i=0;i<5;i++){fn();}extern int x; //調用外部變量printf("x=%d\n",x);return 0; } int x=100;內部函數與外部函數
人本身是有自己的特定方法的,比如當你說話的時候,不希望是別人讓你怎么說你就怎么說吧,那么這種不能被外人調用的方法稱為人的內部方法。人本身還有一些可以調配的方法,比如當你家人跟你說,家里沒有鹽了,你去買袋鹽,去買鹽就是他人調用你的方法,那么能被外人調用的方法稱謂外部方法。
在C語言中不能被其他源文件調用的函數稱謂內部函數 ,內部函數由static關鍵字來定義,因此又被稱謂靜態函數,形式為:
static [數據類型] 函數名([參數])
這里的static是對函數的作用范圍的一個限定,限定該函數只能在其所處的源文件中使用,因此在不同文件中出現相同的函數名稱的內部函數是沒有問題的。
在C語言中能被其他源文件調用的函數稱謂外部函數 ,外部函數由extern關鍵字來定義,形式為:
extern [數據類型] 函數名([參數])
C語言規定,在沒有指定函數的作用范圍時,系統會默認認為是外部函數,因此當需要定義外部函數時extern也可以省略。
字符串函數
注:C語言中不存在字符串變量,字符串只能存在字符數組中。使用這個工具類#include
多維數組的定義
數組:是一塊連續的,大小固定并且里面的數據類型一致的內存空間,在聲明數組后沒有進行初始化的時候,靜態(static)和外部(extern)類型的數組元素初始化元素為0,自動(auto)類型的數組的元素初始化值不確定。另外,二維數組一定要指定列數。
int x[][3] = {{0},{1},{1,2,3}};int x[4][3] = {{1,2,3},{1,2,3},{1,2,3},{1,2,3}}; int x[][3] = {1,2,3,4};linux嵌入式開發
linux嵌入式開發,其實就是用C語言開發的小工具。(例如cd、ls啥的都是linux嵌入式程序),另外,還可以用C語言開發與硬件打交道的程序(例如os(win、linux、ios、android)、arm嵌入式、單片機、arduino),這是因為,C語言有指針,可以直接操縱內存,因此,可以做硬件編程。另外,C語言開發的程序很搞效,nginx就是c寫的,apache是c++寫的,nginx更加高效。
開發環境
mac、linux(ubuntu、centos),ubuntu之所以有amd64,是因為,amd是最早推出64版本的cpu的,因此,沿用了這個說法,現在intel的cpu也是支持ubuntu的。
1.檢查編譯器:cc -v = gcc -v,gcc name1.c name2.c -o xxx.out
2.編譯 gcc -c 文件名 -o 文件名.o
3.gcc max.o hello.c
2.創建文件:touch 文件名
-rwxrwxr-x
其中第一組表示,當前用戶,第二組表示當前組,第三組表示不是當前用戶,也不是當前組
vim
1.shift + i 行首
2.shift + a 行尾
3.o換行
4.shift + o上一行插入
4.dd整行刪除
5.x刪除
6.space * 4 = tab
7.sp打開多個vim界面
8.ctrl + w+下箭頭,就跳轉到了下邊的窗口
9.set nu打開行號
全部格式化 : gg=G
對當前行格式化(縮進): ==
對以下多行格式化(倍數操作): [count] ==
選擇多行后, 執行 等號命令 =
開發
helloworld.c
gcc max.o min.o helloworld.c -o helloworld.o
#include <stdio.h> // 標準的輸入輸出流 #include "max.h" #include "min.h"// 或者把頭文件里的定義放到一個文件中 int main(int argv,char* argc[]) // 不要寫 void了,返回int有意義 {int leftnum = 14;int rightnum = 57;int maxnum = max(leftnum ,rightnum );int minnum = min(leftnum ,rightnum );printf("Hello World\n");printf("max num is %d\n",maxnum);printf("max num is %d\n",minnum );return 0; }main函數的返回值
在linux下,可以通過echo $?,來查看之前執行的程序的返回值,只有返回值為0,才表示執行成功,否則,就是執行失敗。
echo $? 0因此,return 0 ,部署隨便寫的,是有意義的。
main函數的參數
通過參數,可以賦值給不同的參數選項
#include <stdio.h> // 標準的輸入輸出流int main(int argv,char* argc[]) // 不要寫 void了,返回int有意義 {printf("argv is %d\n",argv);int i;for(i=0;i<argv;i++){printf("argc[%d] is %s\n",i,argc[i] );}return 0; }gcc arytes.c -o arykill.o./arykill.o -8 // 操作系統向程序傳遞參數 argv is 2 argc[0] is ./arykill.o argc[1] is -8max.c
gcc -c max.c -o max.o
int max(int a,int b){if(a>b){return a;}else{return b;} }min.c
gcc -c min.c -o min.o
int min(int a,int b){if(a<b){return a;}else{return b;} }max.h
int max(int a,int b);min.h
int min(int a,int b);結果
Hello World max num is 57 max num is 14C語言編譯、組合多文件,自建頭文件
只需要編譯 帶有main函數的那個文件,把不會再修改的函數,放到公共框架內,公共類內,并生成靜態庫,打包放在一起。
makeFile
用make進行編譯,make內部其實使用的也是gcc。通過make把大型開發項目分成若干個模塊。但是,一般情況下,都是使用makefile文件,來進行結構化構建。
對于上方的c語言代碼,我們來進行makefile的構建
# this is make file testmake.o:max.o min.o helloworld.cgcc max.o min.o helloworld.c -o testall.o max.o:max.cgcc -c max.c min.o:min.cgcc -c min.c結果
make && ls gcc -c max.c gcc -c min.c gcc max.o min.o helloworld.c -o testall.out Makefile all.h helloworld.c ji.c max.c max.h max.o min.c min.h min.o testall.c testall.out ./testall.out Hello World max num is 57 max num is 14linux嵌入式標準流
linux介文件
啟動每一個c語言程序,只要include ,就會自動開啟三個處理程序的文件工具stdin(標準輸入流,讀)、stdout(標準輸出流,寫,默認指向顯示器)、stderr(標準錯誤流,報錯)幾個文件。
stdin、stdout、stderr都是文件,其實輸入、輸出、報錯,就是看操作的文件是啥就可以了,都有默認的指向。
#include <stdio.h>int main(){printf("hello world!\n");fprintf(stdout,"please input the value a:\n");int a;scanf("%d",&a);//&a表示取a的地址。fscanf(stdin,"%d",&a);printf("input value is : %d\n",a);if(a<0){fprintf(stderr,"the value must > 0\n");return 500;}return 0; }流的重定向
重定向到文件,可以多次寫入到該文件中 ./a.out 1>> a.txt ls /etc >> etc.txt 重定向到文件,覆蓋寫入到該文件中 ls /etc > etc.txt 重定向到文件,1輸出流,2代表錯誤輸出流 ./a.out 1>t.txt 2>f.txt 重定向文件,輸入流<input.txt ./a.out 1>t.txt 2>f.txt <input.txt管道
|表示一個管道
grep 從輸入(流)的文本文檔中,查詢包含指定字符的行,并顯示到輸出流中
ls /etc/ | grep aa
ps -e | grep ssh
通過管道,將前一個結果的輸出流,作為后一個程序的輸入流。
編寫應用程序并使用管道
自己可以編寫兩個程序,讓其中一個的輸入作為下一個的輸出
前
#include <stdio.h>int main(){int count =0;int s;int w = 0;int flag = 1;while(flag){scanf("%d",&s);if(0==s)break;count++;w+=s; // printf("%d,%d\n",s,count); 切記,只能有一個輸出,否則記錄的是一次的輸出,并將其傳到管道中}printf("%d,%d",w,count);return 0;}后
#include <stdio.h>int main(){int s,n;scanf("%d,%d",&s,&n);float result = s/n;printf("%d個人的平均值是%f\n",n,result);return 0;}結果
./f.o | ./a.out 3000 5000 9000 1234 5678 9999 0 6個人的平均值是5651.000000附錄
閏年
#include <stdio.h> int main() {int year = 2014; //今年是2014年//補全一下代碼if(year%4==0&&(year%100!=0||year%400==0)){printf("今年是閏年");}else{printf("今年是平年");}return 0; }4年一閏,百年不閏,400年再閏(對于數值很大的年份,如果這年能整除3200并且能整除172800則是閏年)
水仙花數
一個三位數,其各位數字立方和等于該數
#include <stdio.h> int main() {//定義三位數num,個位數sd,十位數td,百位數hdint num, sd, td, hd;//循環所有三位數for( num =100 ; num<1000 ; num++ ){//獲取三位數字num百位上的數字hd = num /100 ;//獲取三位數字num十位上的數字td = (num - hd*100)/10 ;//獲取三位數字num個位上的數字sd = num -hd*100 -td*10 ;//水仙花數的條件是什么?if( hd*hd*hd + td*td*td + sd*sd*sd==num ) {printf("水仙花數字:%d\n", num); }}return 0; }輸出個三角
#include <stdio.h> int main() {int i, j, k;for(i=1; i<5; i++){/* 觀察每行的空格數量,補全循環條件 */for(j=i;j<5;j++) {printf(" "); //輸出空格}/* 觀察每行*號的數量,補全循環條件 */for( k=0 ; k<i*2-1 ; k++ ) {printf("*"); //每行輸出的*號}printf("\n"); //每次循環換行}return 0; }****************乘法梯形
#include <stdio.h> int main() { int i, j, result;for(j=9;j>0;j--){for(i=1;i<=j;i++){printf("%d*%d=%d",j,i,j*i);printf(" ");}printf("\n"); }return 0; }9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 4*1=4 4*2=8 4*3=12 4*4=16 3*1=3 3*2=6 3*3=9 2*1=2 2*2=4 1*1=1找出素數(質數)
#include <stdio.h> int main() {int m, n;for(m=2; m<=50; m++){for(n=2; n<m; n++){if( m%n==0 ) //什么條件下跳出當前循環break; //這里應該退出當前循環了} if(m == n) //n循環結束后,如果m=n的話就輸出mprintf("%d ", m);}return 0; }遞歸
遞歸就是一個函數在它的函數體內調用它自身。
計算n的階乘
#include <stdio.h> int factorial(int n){int result; if(n<0) {printf("輸入錯誤!\n"); return 0; }else if(0==n||1==n){ return 1; }else{result =factorial(n-1)*n; }return result; }int main(){ int n=6; printf("%d的階乘=%d\n",n,factorial(n)); return 0;}遞歸函數特點
每一級函數調用時都有自己的變量,但是函數代碼并不會得到復制,如計算5的階乘時每遞推一次變量都不同;
每次調用都會有一次返回,如計算5的階乘時每遞推一次都返回進行下一次;
遞歸函數中,位于遞歸調用前的語句和各級被調用函數具有相同的執行順序;
遞歸函數中,位于遞歸調用后的語句的執行順序和各個被調用函數的順序相反;
遞歸函數中必須有終止語句。
一句話總結遞歸:自我調用且有完成狀態。
例如:
猴子第一天摘下N個桃子,當時就吃了一半,還不過癮,就又多吃了一個。第二天又將剩下的桃子吃掉一半,又多吃了一個。以后每天都吃前一天剩下的一半零一個。到第10天在想吃的時候就剩一個桃子了,問第一天共摘下來多少個桃子?并反向打印每天所剩桃子數。
#include <stdio.h>int getPeachNumber(int n) {int num; //定義所剩桃子數if(n==10){return 1; //遞歸結束條件} else{num = (getPeachNumber(n+1)+1)*2; //這里是不應該用遞歸呢?printf("第%d天所剩桃子%d個\n", n, num); //天數,所剩桃子個數}return num; }int main() {int num = getPeachNumber(1);printf("猴子第一天摘了:%d個桃子。\n", num);return 0; }第9天所剩桃子4個 第8天所剩桃子10個 第7天所剩桃子22個 第6天所剩桃子46個 第5天所剩桃子94個 第4天所剩桃子190個 第3天所剩桃子382個 第2天所剩桃子766個 第1天所剩桃子1534個 猴子第一天摘了:1534個桃子。做遞歸的問題,關鍵是找到突破口。再比如:
有5個人坐在一起,問第5個人多少歲?他說比第4個人大2歲。問第4個人歲數,他說比第3個人大2歲。問第3個人,又說比第2人大兩歲。問第2個人,說比第1個人大兩歲。最后 問第1個人,他說是10歲。請問第5個人多大?
#include <stdio.h> int guessAge(int n){int _age;if(n==1){return 10;}else{_age = guessAge(n-1) + 2;}return _age;}int main() {int _age = guessAge(5);printf("第5個人的年齡是%d歲", _age); return 0; }每日學習單詞
#include <stdio.h> /* 定義獲取單詞數量的函數 */ int getWordNumber(int n) { if(n == 1){return 1; //第一天只會1個單詞}else{return getWordNumber(n-1)+n ; //到第天會的單詞數量} } int main() {int num = getWordNumber(10); //獲取會了的單詞數量printf("小明第10天記了:%d個單詞。\n", num);return 0; }獲取數組長度
#include <stdio.h> int main() {int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};int i = 0;int length = sizeof(arr)/sizeof(arr[0]);for(i = 0;i<length;i++){printf("%d\n",arr[i]);}return 0; }字符串數組
使用%c和%s的技巧不一樣,需要注意。
#include <stdio.h> /* 定義say函數 */ void say(char string[]) //數組參數應該怎么寫呢? {printf("%s\n",string); }int main() {//定義字符串數組char string[] = "我在慕課網上學習IT技能!";int i = 0;//for(;i<sizeof(string)/sizeof(string[0]);i++)//{say(string); //調用say函數輸出字符串//}return 0; }做個排序的題
在一個長度為10的整型數組里面,保存了班級10個學生的考試成績。要求編寫5個函數,分別實現計算考試的總分,最高分,最低分,平均分和考試成績降序排序。
排序請用多種排序方式,此處,沒有實現c語言的數組返回,需要繼續深入學習,后續補充這個文章。
#include <stdio.h>double _Avg(int score[],int _length){int i = 0;double sum = 0;for(;i<_length;i++){sum+=score[i];}if(_length!=0){return sum/_length;}else{return 0.0;} }int* _Desc(int score[],int _length){// int i = 0;// int _desc_score[];// for(;i<_length;i++){// _desc_score[i]=score[i];// }return score; }int main() {int score[]={67,98,75,63,82,79,81,91,66,84};int _length = sizeof(score)/sizeof(score[0]);printf("總分是:%d\n",_Total(score,_length));printf("最高分是:%d\n",_Max(score,_length));printf("最低分是:%d\n",_Min(score,_length));printf("平均分是:%f\n",_Avg(score,_length));printf("NULL-Avg是:%d\n",_Avg(score,NULL));int _desc_score[] =_Desc(score,_length);printf("考試成績降序排序是:");int j = 0;for(;j<_length;j++){printf("%d,",_desc_score[j]);}printf("\n");return 0; }int _Total(int score[],int _length){int i = 0;int sum = 0;for(;i<_length;i++){sum+=score[i];}return sum; }int _Max(int score[],int _length){int i = 0;int _max = 0;for(;i<_length;i++){if(_max<=score[i]){_max = score[i];}}return _max; }int _Min(int score[],int _length){int i = 0;int _min = score[0];for(;i<_length;i++){if(_min>=score[i]){_min = score[i];}}return _min; }計算一年中的第幾天
#include <stdio.h> int main() { /* 定義需要計算的日期 */int year = 2008;int month = 8;int day = 8;/** 請使用switch語句,if...else語句完成本題* 如有想看小編思路的,可以點擊左側任務中的“不會了怎么辦”* 小編還是希望大家獨立完成哦~*/int sum = 0;int i=0;for(i = 0;i<month;i++){switch(i){case 1:sum+=31;break;case 2:sum+=28;break;case 3:sum+=31;break;case 4:sum+=30;break;case 5:sum+=31;break;case 6:sum+=30;break;case 7:sum+=31;break;case 8:sum+=31;break;case 9:sum+=30;break;case 10:sum+=31;break;case 11:sum+=30;break;case 12:sum+=31;break;}} if(year%4==0&&(year%100!=0||year%400==0)){sum+=1;}printf("2008年8月8日是該年的第%d天。",sum+day);return 0; }2008年8月8日是該年的第221天。遺留問題
1.函數如何返回數組或者對象。
2.static靜態的,在C語言中如何深入理解。
3.排序算法和查找算法。
總結
以上是生活随笔為你收集整理的基于c语言的linux嵌入式开发入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: docker如何将运行中的容器保存为do
- 下一篇: Python文件的读写操作