美文网首页
基于c语言的linux嵌入式开发入门

基于c语言的linux嵌入式开发入门

作者: 白昔月 | 来源:发表于2019-10-05 10:03 被阅读0次

    前言

    本文主要包含,c语言基本结构与语法、make及makefile的使用、main函数参数与返回值的说明、标准输入、输出、错误流的介绍以及linux管道的应用。

    语言数据类型

    联合体也有翻译为共用体的,结构类型,也有翻译为结构体的,仅仅是翻译问题,类型是一样的

    每个变量都会占用一定的存储单元。

    image

    符号常量

    100 // 直接常量
    "Hello"
    
    #define PI 3.14 //符号常量
    

    自动类型转换

    image

    强制类型转换

    image

    在使用强制转换时应注意以下问题:

    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+a
    b-b

    小的数字mod 大的数字,余数还是其本身。

    运算符优先级

    图片.png

    爆破彗星是个什么样的游戏?

    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 <string.h>

    image

    多维数组的定义

    数组:是一块连续的,大小固定并且里面的数据类型一致的内存空间,在声明数组后没有进行初始化的时候,静态(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 -8
    

    max.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 14
    
    C语言编译、组合多文件,自建头文件

    只需要编译 带有main函数的那个文件,把不会再修改的函数,放到公共框架内,公共类内,并生成静态库,打包放在一起。

    makeFile

    用make进行编译,make内部其实使用的也是gcc。通过make把大型开发项目分成若干个模块。但是,一般情况下,都是使用makefile文件,来进行结构化构建。

    对于上方的c语言代码,我们来进行makefile的构建

    # this is make file
    testmake.o:max.o min.o helloworld.c
                         gcc max.o min.o helloworld.c -o testall.o
    max.o:max.c
                        gcc -c max.c
    min.o:min.c
                        gcc -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 14
    

    linux嵌入式标准流

    linux介文件

    启动每一个c语言程序,只要include <stdio.h>,就会自动开启三个处理程序的文件工具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,百位数hd
        int 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的话就输出m
                printf("%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;
    
    }
    
    image

    递归函数特点

    每一级函数调用时都有自己的变量,但是函数代码并不会得到复制,如计算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嵌入式开发入门

          本文链接:https://www.haomeiwen.com/subject/tvgjpctx.html