c语言基础

本文详细介绍了C语言中结构体的使用方法,包括结构体成员的访问、结构体数组的定义及初始化,以及如何在驱动设计中运用结构体实现硬件控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.对于结构体的使用,当前值是结构体实体使用 . 符号引用,当前值是结构体指针使用 -> 符号引用

  1.     //定义一个结构体指针  
  2.     struct Student stu;  
  3.     struct Student * student = &stu;  
  4.     stu.score = 90.0f;  
  5.     stu.num = 102;  
  6.     stu.sex = 'F';  
  7.     stu.name = "Amoe";  
  8.     //方法一:用.符号访问  
  9.     printf("num:%d, name:%s, sex:%c, score:%0.2f\n\n",(*student).num, (*student).name, (*student).sex, (*student).score);  
  10.     //方法二:用->符号访问,只要当用结构体指针的时候才可以使用这个操作符  
  11.     printf("num:%d, name:%s, sex:%c, score:%0.2f",student->num, student->name, student->sex, student->score); 

实体变量名.成员=(*指针).成员=指针->成员;所以一般对于指针而言,使用  指针->成员  方式进行访问

 

结构体数组的定义方法:

 

  struct

          char name[8]; 

          char sex[2]; 

          int age; 

          char addr[40]; 

     }student[40];

 

 

     struct string{ 

          char name[8]; 

          char sex[2]; 

          int age; 

          char addr[40]; 

     }; 

     struct string student[40];

存在两个点h文件:a.h和b.h文件,两个文件中均定义了一些类型,若a.h想引用b.h中的类型则需要#include "b.h"  ,若b.h想引用a.h中的类型则需要#include "a.h ",但是若两个文件中均定义了一些类型且两个h都想使用对方的h文件中的类型。这是非法的。因为两个h文件之间的编译是有先后顺序的,先编译a.h文件,必然b.h文件会报错,二先编译b.h文件则必然a.h文件会报错。

 

需要特别注意的是,IAR有时候a.c在工程中编译没有问题,能够直接通过。但是工程中增加一个b.c文件(在其他工程编译没有问题)b.c文件include 了a.h,编译出现错误,而且错误提示为a.c中的一些数据类型没有定义。在b.c中注释 #include a.h。a.c就能编译通过。出现这种情况原因不得而知。可以肯定的是a.c以及b.c中均使用了相同数据类型且都没有勾到定义这些数据类型的定义源文件解决方法就是在a.c以及b.c中均勾到定义数据类型的c.h文件。至于为什么a.c以及b.c均可以使用c.h文件中的数据类型。猜想可能是a.c以及b.c勾到的文件中勾到了c.h,这样a.c以及b.c等于间接勾到了c.h,就能够使用c.h中的数据类型。至于为什么当b.c勾引到a.h的时候就会编译报错?不知道。这里有一个猜想是b.c勾到了a.h,那么b.c到达数据类型的定义文件c.h就有两条路径。编译器无法将两个路径柔和理解为最终指向同一份文件,进而出现报错。

结构体是可以可以直接赋值的,只要结构体类型一致;

二维数组

二维数组的好处就是能够非常直观地展现数据,但是二维数组也有他的使用规则。我们必须按照他的规则办事,否则,编译器会给你报错;其中要说的是二维数组的初始化。二维数组代表的是行列,那么一共有n行就有n个大括号,有m列,则每个大括号里面就有m个元素。二维数组有两种赋值方式:

 

1.int table[2][2]={1,2,3,4};

 

2.int table[2][2]={

{1,2},

{3,4}

};

在这个简单的二维数组中看似两种初始化的方式一样,甚至第一种的初始化使用还显得简单易用。

但是,在一些复杂一点的数据结构上第一种初始化的方式用起来就显得不那么顺手。比如说,结构体二维数组:

//声明一个结构体类型

  typedef struct a

  {

    int a;

    int b;

  }b;

//定义并初始化一个结构体二维数组

  b table[3][4]=

  {

    {{1,1},

    {3,3},

    {4,4},

    {3,3}},

    

    {{1,1},

    {3,3},

    {4,4},

    {3,3}},

 

    {{1,1},

    {3,3},

    {4,4},

    {3,3}}

    

  };//这种方式是可行的,编译器不会报错;

 

但是这种方式:

b table[3][4]={ 

{1,1}, {3,3},{4,4},{3,3},

{1,1}, {3,3},{4,4},{3,3},

{1,1}, {3,3},{4,4},{3,3},

{1,1}, {3,3},{4,4},{3,3} };

会报错,为什么呢?原因是这样的:c语言的语法认为,在二维数组下第一个层级里一个大括号就代表一行数据,所以当二维数组遇上结构体就会出现这样的问题。给结构体赋值是需要大括号的,那按照二维数组赋值的第一种方式,就是很多大括号结构体累积在一起。但是编译器会把它看做是一行的元素,实际上只是一个元素而已;

 

 

驱动的写法

这几天一直在研究2640的驱动,恍然大悟。2640的驱动都是使用一个函数注册表进行封装,利用handle来实现对硬件的控制。基本的思维是这样的:定义一些函数指针类型,再利用这些函数指针类型定义一个函数表结构体类型,一个驱动必然包括硬件、功能表、设计驱动的一些公用协议可选择的部分(例如uart的停止位空闲位等等诸如此类)。前面已经定义好了函数功能表结构体类型(通常用FxnTable表示),需要关于硬件设置的结构体类型(通常用HW表示),公用规范可修改部分(通常用object表示)。这些结构类型定义完成后,定义一个驱动设置表,将他们包含进来。这样在这个设置表里面函数,参数设置,硬件选择都有了。直接用一个handle就能访问到里面的任何东西。而这个handle实际上就是一个驱动设置表类型的指针。整个过程实际上它为底层铺设了一个handle引用系统。应用层调用的时候找到合适的handle就能方便快捷的使用。但是这种写法的一个缺点就是驱动的单线性,同时只能使用一个handel,并线、循环多次使用的情况需要通过应用层的for实现。

一个产品功能分离下来后会形成很多的功能模块,一般而言到这里基本基于平台芯片我们就会开始写这部分的代码。但是实际上功能模块往下继续分离,我们还能继续细分。功能模块往下分我将他分为数据结构算法与平台两部分,若是功能是一个比较通用的功能。平台程序所占又不是非常大的话,考虑将两者分离,这样就可以形成跨平台的功能模块。这个功能模块终究是要与平台接口衔接的。那怎么实现模块与平台分离呢?通过指针函数实现。构建一个平台文件,功能模块调用这个平台文件的接口,这个接口再调用平台提供的接口,这样等于平台文件实现的是给函数指针赋值,更换平台时更换这个接口即可。无线产品会经常涉及到一些通信协议。建议所有的通信协议的解析与生成在一个文件中完成。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值