精华内容
下载资源
问答
  • C语言是一个“古老”编程工具。在嵌入式系统、自控系统及计算机底层操作系统、数据处理中间件等系统开发中仍然是优先...如果你想有效地使用C语言,在系统设计中灵活地应用模块化设计思想,本书是一个很不错参考。
  • C语言是一个“古老”编程工具。在嵌入式系统、自控系统及计算机底层操作系统、数据处理中间件等系统开发中仍然是优先...如果你想有效地使用C语言,在系统设计中灵活地应用模块化设计思想,本书是一个很不错参考。
  • 典型UNIX/Linux操作系统支持多种高级语言这些高级语言包括解释型语言和编译型语言如CC++JavaFortranLISPPascal等而Linux操作系统上大部分应用程序都是基于C语言开发其实Linux操作系统本身也是用C语言开发...
  • 习题 3 参考解答 1.什么是算法常用描述算法的工具有哪些 解 所谓算法就是计算机解决某一个问题的具体方法和步骤常用...什么是结构化程序设计它的主要内容是什么 解 结构化程序设计 structured programming 是进行以模块
  • 有利于程序的模块化 二. 什么叫函数 逻辑上:能够完成特定功能独立代码块 物理上: 能够接受数据(当然也可以不接受) 对接受数据进行处理 能够将数据处理结果返回(当然也可以不返回) 总结:函数是个...

    一. 为什么需要函数

    避免了重复性操作
    有利于程序的模块化
    

    函数是C语言的基本单位,类是Java、C#、C++的基本单位

    C语言没有子程序概念,C语言有函数概念,函数就相当于一个子程序,允许函数单独进行编译,可以实现模块化

    二. 什么叫函数

    逻辑上: 能够完成特定功能的独立的代码块

    物理上:

    • 能够接受数据(当然也可以不接受)
    • 对接受的数据进行处理
    • 能够将数据处理的结果返回(当然也可以不返回)

    总结:函数是个工具,为了解决大量类似问题而设计的,当做一个黑匣子

    三. 函数概述

    对于一个C程序而言,它所有的命令都包含在函数内。每个函数都会执行特定的任务。
    
    一个C程序可由一个主函数和若干个其他函数构成,并且只能有一个主函数。
    
    主函数可以调用其他普通函数,普通函数不能调用主函数,其他普通函数之间也可以相互调用。
    
    主函数是程序的入口,也是程序的出口。
    
    一个函数中不能定义另一个函数,只能调用其他函数
    

    C程序的执行总是从main()函数开始,调用其他函数完毕后,程序流程回到main()函数,继续执行主函数中的其他语句,直到main()函数结束,则整个程序运行结束。

    四. 如何定义函数

    1. C 语言中的函数定义的一般形式如下:
    return_type function_name( parameter list )		//函数头
    {
       body of the function							//函数体( {}之间的内容 )
    }
    
    或
    
    函数返回值类型 函数名(函数的形参列表)
    {
    	函数的执行体
    }
    

    函数由一个函数头和一个函数主体组成。

    2. 示例:
    int add(int a, int b)
    {
        int result;
        rusult = a + b;
        return result;
    }
    

    下面列出一个函数的所有组成部分:

    • 返回类型: 一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不要返回值,在这种情况下,return_type 是关键字 void。
    • 函数名称: 这是函数的实际名称。函数名和参数列表一起构成了函数签名。
    • 形参列表: 参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
    • 函数主体: 函数主体包含一组定义函数执行任务的语句。
    3. 定义函数的本质

    详细描述函数之所以能够实现某个特定功能的具体方法

    4. 形式参数和实际参数
    • 在定义函数时,函数名后面括号中的变量称为:形参

    • 在主调函数中,函数名后面括号中的参数称为:实参

    • 参数的传递

        传递值:
        	函数名(实参列表)
        
        传递引用
        	函数名(&参数)
      
    5. return 表达式; 的含义
    • 终止被调函数,向主调函数返回表达式的值
    • 如果表达式为空,则只终止函数,不向主调函数返回任何值
    • break是用来终止循环和switch语句的,return是用来终止函数的
    6. 返回值类型问题
    • 函数的返回值的类型也称为函数的类型,因为如果函数名前面的返回值类型和函数执行体中的return 表达式中表达式的类型不同的话,则最终函数返回值的类型以函数名前面的返回值类型为准,由系统自动进行强制转换。

    • 当函数没有指明返回值,或没有返回语句时,函数返回一个不确定的值。为了使函数不返回任何值,可以使用void定义无返回值类型函数。

    五. 函数的分类

    在这里插入图片描述

    六. 函数的声明

    注:函数调用和函数定义的顺序

    若函数调用写在了函数定义的前面,则必须加函数前置声明
    

    函数前置声明:

    1. 告诉编译器即将可能出现的若干个字母代表的是一个函数
    2. 告诉编译器即将可能出现若干个字母所代表的函数的形参和返回值的具体情况
    3. 函数声明是一个语句,末尾必须加分号
    4. 对于库函数的声明通过 #include <库函数所在的文件的名字.h> 来实现

    七. 函数的调用

    1. 函数调用的一般形式:函数名(实参列表);

    2. 函数调用分类:

      • 调用无参函数:函数名();

      • 调用有参函数:函数名(实参列表);

          若实参列表中有多个实参,各参数间用逗号隔开
          C调用函数是,只能传值给函数形参
          形参和实参必须个数相同、位置一一对应、数据类型必须相互兼容
        
      • 举例

        #include <stdio.h>
        
        /* 函数声明 */
        int max(int num1, int num2);
        
        int main()
        {
            /* 局部变量定义 */
            int a = 100;
            int b = 200;
            int ret;
        
            /* 调用函数来获取最大值 */
            ret = max(a, b);
        
            printf("Max value is : %d\n", ret);
        
            return 0;
        }
        
        /* 函数:返回两个数中较大的那个数 */
        int max(int num1, int num2)
        {
            /* 局部变量声明 */
            int result;
        
            if (num1 > num2)
                result = num1;
            else
                result = num2;
        
            return result;
        }		
        
    3. 函数的嵌套调用

      C语言的函数定义都是独立的、互相平行的,C语句不允许嵌套定义函数,即一个函数内不能定义另一个函数,但可以嵌套调用函数,即在调用一个函数的过程中,又调用另一个函数。

    4. 函数的递归调用

      • 定义:在调用一个函数的过程中又出现直接或间接调用该函数自己的。

      • 递归满足的三个条件:

          递归必须得有一个明确的中止条件;
          该函数所处理的数据规模必须在递减(值可以增加);
          这个转化必须是可解的;
        
      • 举例

        //下面的实例使用递归函数生成一个给定的数的斐波那契数列:
        #include <stdio.h>
         
        int fibonaci(int i)
        {
           if(i == 0)
           {
              return 0;
           }
           if(i == 1)
           {
              return 1;
           }
           return fibonaci(i-1) + fibonaci(i-2);
        }
         
        int  main()
        {
            int i;
            for (i = 0; i < 10; i++)
            {
               printf("%d\t\n", fibonaci(i));
            }
            return 0;
        }
        
        

    八. 数组作为函数参数

    调用有参函数时,需要提供实参
    例如:sin(x)、sqrt(2.0)、max(a,b)

    实参可以是常量、变量或表达式
    数组元素的作用与变量相当,一般来说,凡是变量可以出现的地方,都可以用数组元素代替

    1.数组元素也可以用作函数实参,其用法与变量相同,向形参传递数组元素的值
    2. 数组名也可以作为实参和形参,传递的是数组第一个元素的地址

    1. 数组元素作为函数实参

    数组元素可以作为函数的实参,与用变量作为实参一样,按照单向值传递的方式进行传递

    数组元素不能作为形参,因为形参是在函数被调用时临时分配存储单元的,不可能为一个数组元素单独分配存储单元

    /*
    输入10个数,要求输出其中值最大的元素和该数是第几个数 
    */
    #include <stdio.h>
    
    int max(int x, int y)
    {
    	return (x>y? x:y);
    }
    
    int main(void)
    {
    	int a[10],m,n,i;
    	
    	for(i=0; i<10; i++)
    	{
    		scanf("%d", &a[i]);
    	}
    	printf("\n");
    	
    	for(i=1,m=a[0],n=0;i<10;i++)
    	{
    		if(max(m,a[i])>m)		//若max函数返回的值大于m 
    		{
    			m=max(m,a[i]);		//max函数返回的值取代m原值
    			n=i; 
    		}
    	}
    	printf("The largest number is %d\n it is the %dth number.\n", m, n+1); 
    	
    	return 0;	
    } 
    

    2. 数组名可以作为函数参数

    可以用数组名作为函数参数,此时实参与形参都应该用数组名,此时的数组名是整个数组的首地址

    向形参(数组名或指针变量)传递的是数组首元素的地址

    (1). 一维数组名作函数参数

    /*
    题目:有一个一维数组score,内放10个学生成绩,求平均成绩
    结论:
    1. 用数组名作函数参数,应该在主调函数和被调函数分别定义数组 
    2. 实参数组和形参数组类型应一致
    3. 形参数组名获得实参数组的首元素的地址,因为数组名代表数组的首元素的地址
    	所以可以认为,形参数组首元素(array[0])和实参数组首元素(score[0])具有同一地址
    	他们共同占用同一存储单元,score[n]和array[n]指的是同一单元,它两具有相同的值
    	形参数组中各元素的值发生变化会使得实参数组元素的值同时发生变化 
    4. 形参数组可以不指定大小,在定义数组时再数组名后面跟一个空的方括号 
    */
    #include <stdio.h>
    
    float average(float array[10])	//array形参数组名 
    	//如下写法正确:float average(float array[])	 定义的average函数,形参数组不指定大小 
    /*
    以上原因的本质是:系统对源程序进行编译时,编译系统会把形参数组处理为指针变量
    即把float array[] 转换为float * array,该指针变量用来接收从实参数组传过来的地址
    所以以上两者是等价的,对数组元素的访问,用下标和指针也是完全等价的
    使用形参数组是为了便于理解,形参数组与实参数组各元素一一对应 
    */ 
    
    {
    	int i;
    	float aver;
    	float sum=array[0];
    	
    	for(i=1;i<10;i++)
    	{
    		sum=sum+array[i];
    	}
    	aver=sum/10;
    	return aver;
    }
    
    int main(void)
    {
    	float score[10];
    	float aver;
    	int i;
    	
    	for(i=0;i<10;i++)
    	{
    		scanf("%f", &score[i]);		//score是实参数组名 
    	}
    	printf("\n");
    	aver=average(score);		//调度average函数 
    	
    	printf("average score is %5.2f\n", aver);
    	return 0;
    	
    	return 0;	
    } 
    

    (2). 多维数组名作函数参数

    多维数组名作为函数的实参和形参,在被调函数中对形参数组定义时可以指定每一维的大小

    例如:int array[3][10];
    

    也可以省略第一维的大小说明

    例如:int array[][10];
    

    原因是:二维数组是由若干个一维数组组成的,在内存中,数组是按行存放的,因此在定义二维数组时,必须指定列数(即一行中包含几个元素)由于形参数组与实参数组类型相同,所以他们是由具有相同长度的一维数组所组成的,不能只指定第一维,而省略第二维
    在这里插入图片描述

    在第二维大小相同的前提下,形参数组的第一维可以与实参数组不同

    例如:
    	实参数组定义为 int score[5][10]
    	形参数组定义为 int array[][10] 或 int array[8][10]
    
    这时候形参数组和实参数组都是由相同类型和大小的一维数组组成,C语言编译不检查第一维大小
    
    /*
    题目:有一个3*4的矩阵,求所有元素中的最大值 
    结论:
    在主调函数,把实参二维数组a的第1行的起始地址传递给形参数组array
    所以array数组第一行起始地址和a数组第一行起始地址相同
    由于两个数组列数相同,所以a[i][j]与array[i][j]同占一个存储单元,
    他们本质上是相同的,对形参数组操作就是对实参数组操作 
    */
    #include <stdio.h>
    
    int max_value(int array[][4])
    {
    	int i,j,max;
    	max=array[0][0];
    	for(i=0;i<3;i++)
    		for(j=0;i<3;j++)
    		{
    			if(array[i][j]>max)
    				max=array[i][j]		//把最大值放在max中 
    		}
    	return 0;
    }
    
    int main(void)
    {
    	int a[3][4]={{1,3,5,7},{2,4,6,8},{15,17,34,12}};	//对数组元素进行赋值
    	printf("Max value is %d\n", max_value(a));	//调用函数 
    	
    	return 0;	
    } 
    

    九. 变量的作用域和存储方式

    一个变量的生存期(作用域)在一个块内存在/生效
    块就是一个{ }
    一个块里面只能定义一个名字的变量

    1. 按作用域分:

    • 全局变量

        定义:在所有函数外部定义的变量
        使用范围:从定义位置开始到整个程序结束
      
    • 局部变量

        定义:在一个函数内部定义的变量或者函数的形参		
      
      /* 例如 */
      void f(int i)
      {
      	int j=20;
      }
      /* i和j都是局部变量 */
      

      使用范围:只能在本函数内部使用

    • 注:全局变量和局部变量命名冲突问题

        在一个函数内部如果定义的局部变量的名字和全局变量的名字一样时,局部变量会屏蔽掉全局变量
      
    • 举例

      #include <stdio.h>
      
      /*
      此程序用来判断主函数里面实参变量i和子函数里面的形参变量i是不是同一个变量
      说明形参和实参不是一个变量
      修改形参的值,不影响实参的值,因为他们作用的范围不同
      程序从main函数进入之后,分配了i变量的空间,当进行f()函数调用,又为f函数分配了另外一块存储空间,
      	当f函数执行完之后,分配给f的函数空间就会被释放,所以普通子函数不能改变主函数的值 
      */
      void f(int i)
      {
      	i = 99;		//i是局部变量
      }
      
      int main(void)
      {
      	int i = 6;	//i是局部变量
      	printf("i = %d\n", i);
      	f(i);
      	printf("i = %d\n", i);
      	
      	return 0;	
      }
      /*
      结果: 
      i = 6
      i = 6
      */
      

    2. 按变量的存储方式分:

    • 静态变量
      当函数体内部用static来说明一个变量时,可以称该变量为静态局部变量。

      它与auto变量、register变量的本质区别:

        在整个程序运行期间,静态局部变量在内存中的静态存储区中占据着永久性的存储单元,
        即使退出函数后下次再进入该函数时,静态局部变量仍然使用原来的存储单元。
        由于不释放这些存储单元,这些存储单元中的值得以保存,因而可以继续使用存储单元中原来的值
      
        静态局部变量的初值是在编译时赋予的,在程序执行期间不再赋以初值,
        对未赋值的局部变量,C语言编译程序自动给他赋初值为0.
      
    • 自动变量(auto变量)
      当函数内部或复合语句内定义变量是,如果没有指定存储类型,或使用了auto说明符,系统就认为所定义的变量具有自动类别。

    • 寄存器变量(register变量)
      寄存器变量也是自动类变量,它与auto变量的区别仅在于:用register说明变量是建议编译程序将变量的值保存在CPU的寄存器中,而不是像一般变量那样占用内存单元。

    十. 如何在软件开发中合理设计函数来解决实际问题

    方法要求:

    一个函数的功能尽量独立、单一
    多学习,多模仿牛人的代码

    十一. 常用的系统函数

    double sqrt(double x);	求x的平方根
    int sbs(int x);			求整数x的绝对值
    double fabs(double x)	求浮点数x的绝对值
    
    展开全文
  • 模块化程序设计

    2020-09-02 19:57:07
    1 模块化程序设计 在程序设计过程中,有一个很重要思想是:程序功能...在讲解第一个C语言程序例子时候,我们就接触到了“函数”;并且知道,函数就像是一个工具,我们可以用它来完成某项工作。我们再来看看这个

    1 模块化程序设计

    在程序设计的过程中,有一个很重要的思想是:程序功能模块化。就是对程序的功能进行划分,每一个功能模块使用一个函数来封装实现。

    例如,开发一个图书馆管理系统,这个系统涉及到学生借书、还书的操作。那么,把借书和还书分解成一个独立的功能模块,每个功能模块使用独立的函数来实现。

    所以,下面我们介绍函数的定义和使用,灵活使用函数来设计程序。

    2 引出函数定义

    在讲解第一个C语言程序例子的时候,我们就接触到了“函数”;并且知道,函数就像是一个工具,我们可以用它来完成某项工作。我们再来看看这个程序的代码,代码如下:

     

    可以看到,在这个程序中,用到了三个函数,有main函数、printf函数、system函数;其中,main函数是我们自己定义的函数,printf函数和system函数是Linux系统提供的函数。其中Linux系统提供的函数会封装到一个库中,通过库的方式给用户使用,所以,也称为:库函数。

    所以,从函数定义的角度来讲,函数可以分为:用户自定义函数库函数

    (1) 用户自定义函数:就是我们自己使用C语言来编写定义和实现的函数,例如main函数,就是我们自己定义的函数。

    (2) 库函数:就是C语言系统提供的函数,例如printf函数,我们不需要定义和实现它;可以直接使用它。

    举个例子,我们在吃饭的时候,都需要使用筷子;那么,想方便的话,可以直接到超市买一次性的筷子,此时,我们就拥有了一双筷子,可以用来吃饭。可以看到,筷子就是一个工具,我们可以使用这个工具来完成吃饭。

    但是,有一天,我们觉得超市的一次性筷子不卫生健康,那么,就到山上砍了竹子,自己做了一双纯天然的筷子。此时,我们就拥有了自己做的一双筷子,它也是一个工具,我们可以用它来完成吃饭。但是,这双筷子是我们自己做的筷子,而不是从超市买来的筷子。

    那么,通过这个例子,我们可以归纳类比:

    (1) 我们从超市买来的筷子,就如同库函数,不需要自己定义,可以直接拿来使用;

    (2) 我们自己做的筷子,就如同用户自定义函数,是用户自己定义制作出来的函数; 

    (3) 无论是从超市买来的一次性筷子,还是我们制作的筷子,都是一个工具,都可以用来完成吃饭。所以,函数也就是一个工具,我们可以用它来完成某一项工作;

    展开全文
  • 问题描述:使用较多嵌入式C语言开发工具是Keil,但程序的开发不仅仅是完成功能就了事这么简单,后期还需要不断改善和维护才行,这所花时间估计会远远大于初步开发完成基本功能所用时间。为了方便程序的...
    问题描述:使用较多的嵌入式C语言开发工具是Keil,但程序的开发不仅仅是完成功能就了事这么简单的,后期还需要不断的改善和维护才行,这所花的时间估计会远远大于初步开发完成基本功能所用的时间。为了方便程序的规范、可读、易于维护,模块化设计是很有用处的,那样即使不是代码开发者本人,换成其他人来维护也不至于头疼。下面将记录一些嵌入式C语言工程文件的组织的问题,便于对程序进行模块化,但都比较简单,以后有新的经验再继续更新。
    
        文件组织:我一般分为Output,Listing和source_code。包含这几个子目录的是以程序名命名的文件夹。首先在该文件夹下新建一个工程,添加启动代码。子目录Output是用来存放工程输出文件的,Listing是存放链接.lst文件的,source_code下面就是源代码了,可以根据功能的不同继续进行子目录的创建。
        文件引用与对应:这里引用是指如何include不在同一文件目录下的头文件,具体是用"..\"的方式,如source_code文件夹下有a,b两个子文件夹,a存放了应用程序代码,b存放了接口文件,要在a中使用b中接口文件head1.h提供的接口函数时,可以include对应的头文件,由于不在同一文件夹中,可以使用#include "../b/head.h"。其中".."意思是指上层文件夹目录,另外"."指本层文件夹目录。
        文件对应是指在工程选项中将Output指定为输出文件存放的文件夹,将Listing指定为链接文件存放的文件夹。
        如何包含接口文件:这里的接口文件就是指c里面的.h头文件。uCOS中建议的方法是用一个INCLUDE.h将所有头文件都包含进来,这样就不必详细的根据模块的需要来一个个包含了,uCOS中指出该方法的唯一缺点是编译时间要更长。但是总觉得这样对c的模块化还是不太有利的,最好还是详细知道各个接口文件都提供了什么,然后根据自己的需要去一个个的包含,虽然这样更耗时。
        模块:C程序设计需将其看作是一些独立的模块。模块是一组服务的集合,其中一些服务可以被程序的其他部分使用。每个模块都有一个接口来描述所提供的服务。模块的类型可以分为:数据池、库、抽象对象、抽象数据类型(ADT)。
        对于不同功能的模块,尽量用一个.c和一个.h文件划分该模块,.h文件用于一些宏定义、全局函数的声明,.c文件中就是具体的代码实现了,包括子函数、变量等。这样做能重用各模块,针对不同的应用程序只需要调用相应模块实现功能即可,不用从头到尾又一遍的重新编写各个功能的实现。
        一个嵌入式系统一般包括两类模块:硬件驱动模块(针对一种特定硬件的模块)和软件功能模块(保持低耦合、高内聚要求)。
        模块接口的设计不是随意的声明集合,需要考虑高内聚性与低耦合性。高内聚性指模块中元素应彼此紧密相关,使模块更易于使用,使程序更易于理解。低耦合性指模块之间应尽可能相互独立,使程序更易于修改,方便复用模块。
        模块的设计:
        一. 头文件编写基本原则:
        1. 头文件中不能有可执行代码,也不能有数据的定义,只能有宏、类型(typedef,struct,union,menu),数据和函数的声明。
        这个很好理解,只进行宏定义、数据类型和函数的声明不会开辟内存,声明是编译器需要。而在头文件中定义则需要开辟内存的,这样导致每个包含该接口的文件都分配一次内存了。
        2. 头文件中不能包含本地数据(模块自己使用的数据或函数,不被其他模块使用)。
        这一点相当于面向对象程序设计里的私有成员,即只有模块自己使用的函数,数据,不要用extern在头文件里声明,只有模块自己使用的宏,常量,类型也不要在头文件里声明,应该在自己的*.c文件里声明。这也是称.h文件为接口声明的原因,好的模块设计使使用者只需关注.h文件提供的接口进行调用即可。
           3. 含一些需要使用的声明。
           在头文件里声明外部需要使用的数据,函数,宏,类型。
           4. 防止被重复包含。
           使用#ifndef宏防止一个头文件被重复包含。
           二、头文件编写参考更多的规则
           1. 一个模块一个接口,不能几个模块用一个接口。
           即模块要进行很好的内聚性设计,每个模块相对独立。如果多个模块一个接口就会显得比较混乱。
           2. 文件名为和实现模块的c文件相同。
           如abc.c--abc.h,这样便于程序的设计和维护,一目了然的知道某一个模块。
           3. 尽量不要使用extern来声明一些共享的数据。
           因为这种做法是不安全的,外部其他模块的用户可能不能完全理解这些变量的含义,最好提供函数访问这些变量。全局变量的使用特别在工程代码很多的时候容易出问题,许多时候在任何地方都有可能多次对全局变量进行了改变,而且是在不同的函数模块中,这样编程时查找或调试都会有许多问题。使用函数进行访问,即是参考了面向对象中封装的思想,一个函数get获取,一个set函数设置,查找起来也方便。
           4. 尽量避免包含其他的头文件,除非这些头文件是独立存在的。
           这一点的意思是,在作为接口的头文件中,尽量不要包含其他模块的那些暴露*.C文件中内容的头文件,但是可以包含一些不是用来暴露接口的头文件。在实际使用中这样会导致编译器一些莫名的问题,有时可能是重复定义错误,有时可能是缺少定义错误。
           5. 不要包含那些只有在可执行文件中才使用的头文件,这些头文件应该在*.c文件中包含。
           这一点如同上一点,为了提高接口的独立性和透明度。
           6. 接口文件要有面向用户的充足的注释。
           从应用角度描述个暴露的内容。
           7. 接口文件在发布后尽量避免修改,即使修改也要保证不影响用户程序。
           三、多个代码文件使用一个接口文件
           这种头文件用于那些认为一个模块使用一个文件太大的情况。对于这种情况在参考上述建议后,也要参考以下建议。
           1. 多个代码文件组成的一个模块只有一个接口文件。因为这些文件完成的是一个模块。
           2. 使用模块下文件命名 <系统名> <模块名命名>
           3. 不要滥用这种文件。
           4. 有时候也会出现几个*.c文件用于共享数据的*.h文件,这种文件的特点是在一个*.c文件里定义全局变量,而在其他*.c文件里使用,要将这种文件和用于暴露模块接口的文件区别。
           5. 一个模块如果有几个子模块,可以用一个*.h文件暴露接口,在这个文件里用#include包含每个子模块的接口文件。
           四、说明性头文件的使用
           说明性头文件,这种头文件不需要有一个对应的代码文件,在这种文件里大多包含了大量的宏定义,没有暴露的数据变量和函数。
           1. 包含一些需要的概念性的东西。
           2. 命名方式,定义的功能.h
           3. 不包含任何其他的头文件。
           4. 不定义任何类型。
           5. 不包含任何数据和函数声明
           五、C代码文件.c的使用建议
           *.c文件是C语言中生成汇编代码和机器码的内容。
           1.命名方式 模块名.c
           2,用static修饰本地的数据和函数。
           3,不要使用extern
           这是在*.h中使用的,可以被包含进来。
           4,无论什么时候定义内部的对象,确保独立与其他执行文件。
           5,这个文件里必须包含相应功能函数。
           模块化设计可以参考更多的面向对象和COM的思想。
    展开全文
  • 问题描述:使用较多嵌入式C语言开发工具是Keil,但程序的开发不仅仅是完成功能就了事这么简单,后期还需要不断改善和维护才行,这所花时间估计会远远大于初步开发完成基本功能所用时间。为了方便程序的...
       问题描述:使用较多的嵌入式C语言开发工具是Keil,但程序的开发不仅仅是完成功能就了事这么简单的,后期还需要不断的改善和维护才行,这所花的时间估计会远远大于初步开发完成基本功能所用的时间。为了方便程序的规范、可读、易于维护,模块化设计是很有用处的,那样即使不是代码开发者本人,换成其他人来维护也不至于头疼。下面将记录一些嵌入式C语言工程文件的组织的问题,便于对程序进行模块化,但都比较简单,以后有新的经验再继续更新。
       文件组织:我一般分为Output,Listing和source_code。包含这几个子目录的是以程序名命名的文件夹。首先在该文件夹下新建一个工程,添加启动代码。子目录Output是用来存放工程输出文件的,Listing是存放链接.lst文件的,source_code下面就是源代码了,可以根据功能的不同继续进行子目录的创建。
       文件引用与对应:这里引用是指如何include不在同一文件目录下的头文件,具体是用"..\"的方式,如source_code文件夹下有a,b两个子文件夹,a存放了应用程序代码,b存放了接口文件,要在a中使用b中接口文件head1.h提供的接口函数时,可以include对应的头文件,由于不在同一文件夹中,可以使用#include"../b/head.h"。其中".."意思是指上层文件夹目录,另外"."指本层文件夹目录。
       文件对应是指在工程选项中将Output指定为输出文件存放的文件夹,将Listing指定为链接文件存放的文件夹。
       如何包含接口文件:这里的接口文件就是指c里面的.h头文件。uCOS中建议的方法是用一个INCLUDE.h将所有头文件都包含进来,这样就不必详细的根据模块的需要来一个个包含了,uCOS中指出该方法的唯一缺点是编译时间要更长。但是总觉得这样对c的模块化还是不太有利的,最好还是详细知道各个接口文件都提供了什么,然后根据自己的需要去一个个的包含,虽然这样更耗时。
       模块:C程序设计需将其看作是一些独立的模块。模块是一组服务的集合,其中一些服务可以被程序的其他部分使用。每个模块都有一个接口来描述所提供的服务。模块的类型可以分为:数据池、库、抽象对象、抽象数据类型(ADT)。
       对于不同功能的模块,尽量用一个.c和一个.h文件划分该模块,.h文件用于一些宏定义、全局函数的声明,.c文件中就是具体的代码实现了,包括子函数、变量等。这样做能重用各模块,针对不同的应用程序只需要调用相应模块实现功能即可,不用从头到尾又一遍的重新编写各个功能的实现。
      一个嵌入式系统一般包括两类模块:硬件驱动模块(针对一种特定硬件的模块)和软件功能模块(保持低耦合、高内聚要求)。
      模块接口的设计不是随意的声明集合,需要考虑高内聚性与低耦合性。高内聚性指模块中元素应彼此紧密相关,使模块更易于使用,使程序更易于理解。低耦合性指模块之间应尽可能相互独立,使程序更易于修改,方便复用模块。
       模块的设计:
        一.头文件编写基本原则:
       1.头文件中不能有可执行代码,也不能有数据的定义,只能有宏、类型(typedef,struct,union,menu),数据和函数的声明。
      这个很好理解,只进行宏定义、数据类型和函数的声明不会开辟内存,声明是编译器需要。而在头文件中定义则需要开辟内存的,这样导致每个包含该接口的文件都分配一次内存了。
       2.头文件中不能包含本地数据(模块自己使用的数据或函数,不被其他模块使用)。
       这一点相当于面向对象程序设计里的私有成员,即只有模块自己使用的函数,数据,不要用extern在头文件里声明,只有模块自己使用的宏,常量,类型也不要在头文件里声明,应该在自己的*.c文件里声明。这也是称.h文件为接口声明的原因,好的模块设计使使用者只需关注.h文件提供的接口进行调用即可。
          3. 含一些需要使用的声明。
          在头文件里声明外部需要使用的数据,函数,宏,类型。
          4. 防止被重复包含。
          使用#ifndef宏防止一个头文件被重复包含。
          二、头文件编写参考更多的规则
          1. 一个模块一个接口,不能几个模块用一个接口。
          即模块要进行很好的内聚性设计,每个模块相对独立。如果多个模块一个接口就会显得比较混乱。
          2. 文件名为和实现模块的c文件相同。
          如abc.c--abc.h,这样便于程序的设计和维护,一目了然的知道某一个模块。
          3. 尽量不要使用extern来声明一些共享的数据。
          因为这种做法是不安全的,外部其他模块的用户可能不能完全理解这些变量的含义,最好提供函数访问这些变量。全局变量的使用特别在工程代码很多的时候容易出问题,许多时候在任何地方都有可能多次对全局变量进行了改变,而且是在不同的函数模块中,这样编程时查找或调试都会有许多问题。使用函数进行访问,即是参考了面向对象中封装的思想,一个函数get获取,一个set函数设置,查找起来也方便。
          4. 尽量避免包含其他的头文件,除非这些头文件是独立存在的。
          这一点的意思是,在作为接口的头文件中,尽量不要包含其他模块的那些暴露*.C文件中内容的头文件,但是可以包含一些不是用来暴露接口的头文件。在实际使用中这样会导致编译器一些莫名的问题,有时可能是重复定义错误,有时可能是缺少定义错误。
          5.不要包含那些只有在可执行文件中才使用的头文件,这些头文件应该在*.c文件中包含。
          这一点如同上一点,为了提高接口的独立性和透明度。
          6. 接口文件要有面向用户的充足的注释。
          从应用角度描述个暴露的内容。
          7. 接口文件在发布后尽量避免修改,即使修改也要保证不影响用户程序。
          三、多个代码文件使用一个接口文件
          这种头文件用于那些认为一个模块使用一个文件太大的情况。对于这种情况在参考上述建议后,也要参考以下建议。
          1.多个代码文件组成的一个模块只有一个接口文件。因为这些文件完成的是一个模块。
          2. 使用模块下文件命名 <系统名><模块名命名>
          3. 不要滥用这种文件。
          4.有时候也会出现几个*.c文件用于共享数据的*.h文件,这种文件的特点是在一个*.c文件里定义全局变量,而在其他*.c文件里使用,要将这种文件和用于暴露模块接口的文件区别。
          5.一个模块如果有几个子模块,可以用一个*.h文件暴露接口,在这个文件里用#include包含每个子模块的接口文件。
          四、说明性头文件的使用
          说明性头文件,这种头文件不需要有一个对应的代码文件,在这种文件里大多包含了大量的宏定义,没有暴露的数据变量和函数。
          1. 包含一些需要的概念性的东西。
          2. 命名方式,定义的功能.h
          3.不包含任何其他的头文件。
          4. 不定义任何类型。
          5. 不包含任何数据和函数声明
          五、C代码文件.c的使用建议
          *.c文件是C语言中生成汇编代码和机器码的内容。
          1.命名方式 模块名.c
          2,用static修饰本地的数据和函数。
          3,不要使用extern
          这是在*.h中使用的,可以被包含进来。
          4,无论什么时候定义内部的对象,确保独立与其他执行文件。
          5,这个文件里必须包含相应功能函数。
          模块化设计可以参考更多的面向对象和COM的思想。
    展开全文
  • 本书是针对目前最通用单片机8051和目前最流行程序设计语言C,以Franklin/KeilC51编译器为工具,讲解单片机的C语言程序设计教材。全书共十三章,既有单片机基础知识部分;C5l P6基础部分:数据与运算控制...
  • 关键词:C语言 函数程序模块字义声明调用C语言是国内外广泛使用的一种计算机语言,是计算机应用人员应掌握的一种程序设计工具C语言是一种高级语言,采用结构化的程序设计方法:自顶向下、逐步细化、模块化设计、...
  • C语言基础知识

    2016-08-24 14:19:36
    1:c语言模块化,结构化的程序设计语言 2:用高级语言进行程序设计,其编程效率高,方便易用,但执行速度没有低级语言高 3:第一个系统体现结构化程序设计思想的教学工具是pascal
  • C语言简历

    千次阅读 2017-10-17 21:44:12
    C语言的起源 1972年在贝尔实验室 ...1、层次清晰,便于按模块化方式组织程序,易于调试和维护 2、结构化的缺点很明显,程序的可重用很差 3、语言非常简洁,适合编程的入门语言,使用灵活方便 可移植性好 不同机器
  • 随着单片机硬件性能的提高,编写应用程序...一、C51语言程序设计的基本技巧首先,C51语言程序设计要尽可能采用结构化的设计方法。可将整个程序按功能分成若干个模块,不同的模块完成不同的功能。对于不同的功能模块...
  • C语言函数

    2021-03-16 21:32:06
    有利于程序的模块化 二.什么是函数 逻辑上: 能够完成特定功能独立代码块 物理上: 能够接收数据(也可以不接收数据) 能够对接收数据进行处理 能够将数据处理结果返回(也可以不返回任何值) 总结: 函数是个...
  • C语言中,函数又可以被称为 “子程序”,它是一个大程序的某一个部分,由一个或多个语句块构成,负责完成某项特定任务,而且相较于其他代码,其具备相对独立性,可以用它来实现代码的模块化。 函数分类 1.库函数...
  • C语言的科学和艺术.pdf

    热门讨论 2012-01-19 14:09:05
    第一部分 c语言程序设计基础 .第2章 通过例子学习 16 2.1 “hello world”程序 17 2.1.1 注释 17 2.1.2 库包含 18 2.1.3 主程序 18 2.2 两个数加法程序 20 2.2.1 输入阶段 21 2.2.2 计算阶段 23 2.2.3 ...
  • 模块化合成工具包(MSK,libmsk)–一个独立库,能够对综合系统进行建模和运行; 该库是通过API控制,唯一要求就是可移植性库Glib。 图形MSK编辑器(GMSK,libgmsk)–一个库,在libmsk上添加了一层,为其...
  • C语言大纲及课件

    2014-03-27 19:26:42
     了解:运用函数知识实现模块化程序设计  ⑻ 指针  掌握:指针基本概念,指针变量定义、引用、运算及操作,给指针变量赋值、移动指针、指针比较、通过指针变量引用存储单元;函数调用参数为指针变量时,...
  • 第一章 初始C语言

    2021-03-28 09:16:37
    设计特性:C语言的设计理念让用户能轻松地完成自顶向下规划、结构化编程和模块化设计。用C编写的程序更易懂、更可靠。 高效性:C是高效语言。C程序紧凑、运行速度快。具有汇编语言微调控制能力。 可移植性:在一...
  • c语言学习笔记(8)——函数

    千次阅读 2013-08-06 21:25:27
    2.有利于程序的模块化(每一个功能可以用不同函数去实现) 二、什么叫做函数? 逻辑上:能够完成特点功能独立代码单元 物理上:能够接收数据 能够对接收数据进行处理 能够将处理结果返回 总结: 函数是...
  • C语言接口与实现:创建可重用软件技术.pdf

    千次下载 热门讨论 2011-09-30 17:46:11
    它可以作为下一代软件的工具书.所有的c语言程序员都应该阅读。  ——w.richard stevens  “我向每位专业c语言程序员推荐这本书。c语言程序员们忽视书中所描述的各种技术已经太长时 间了。”  ——norman ...
  • c语言整理makefile

    2020-05-21 13:22:40
    在linux中,有一个实用程序,叫make,可以用它来管理多模块程序的编译和链接,直至生成可执行文件。 make程序的编译规则说明文件,称为makefile,makefile文件中描述了整个软件工程编译规则和各个文件之间依赖...
  • C语言编辑器mytc5.6

    2009-05-10 12:25:39
    5、在 MyTC 环境下您可以将你经常用到的程序模块组织成以'.h'为后缀头文件保存在安装目录‘include'目录下方便以后调用。6、附C语言教程、C源码格式化工具; 2.本版本为免安装绿色版,不依赖于具体机器,可拷贝到...
  • 学习本门课程主要应掌握C语言程序设计基础、C语言模块化程序设计方法、VC++ 6.0集成开发环境使用方法,学生在了解C语言程序设计基础、掌握VC++ 6.0集成开发环境使用方法之后,便可采用模块化程序设计方法来进行...
  • c语言初学者入门讲座

    2009-07-03 16:28:29
    面向对象编程和可视集成开发工具的发展,使很多曾经非常流行编程语言影响下降甚至逐步消失,但有一种语言是例外,它就是C语言,时光流逝丝毫没减低C魅力,它风采依然如旧。  C语言已经深深进入各种操作...
  • c语言编写单片机技巧

    2009-04-19 12:15:17
    此外,C语言程序具有完善模块程序结构,从而为软件开发中采用模块化程序设计方法提供了有力保障。因此,使用C语言进行程序设计已成为软件开发一个主流。用C语言来编写目标系统软件,会大大缩短开发周期,且...
  • C语言初学者入门讲座

    2008-10-31 20:01:59
     面向对象编程和可视集成开发工具的发展,使很多曾经非常流行编程语言影响下降甚至逐步消失,但有一种语言是例外,它就是C语言,时光流逝丝毫没减低C魅力,它风采依然如旧。  C语言已经深深进入各种...
  • C语言学习笔记05-函数

    2020-07-30 20:44:31
    有利于程序的模块化 函数是C语言的基本单位 什么叫做函数? 逻辑上: 能够完成特定功能独立代码块 物理上: 能够接收数据(也可以不接收) 能够对接收数据进行处理 能够将数据处理结果返回(可以不返回) ...
  • c语言之函数(重点)

    2014-06-26 21:35:00
    有利于程序的模块化(把问题分解,每个问题用函数解决) 什么叫函数 逻辑上:能够完成特定功能独立代码块 物理上:能够接收数据、能够对接收数据进行处理、能够将数据处理结果返回(函数接受值数据类型、...

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 213
精华内容 85
关键字:

c语言程序模块化的工具是

c语言 订阅