C语言——结构体
宗旨:技术的学习是有限的,分享的精神是无限的。
1、结构体的作用:个人理解,结构体就是把一堆相关的数据打包成一个结构,使其放在一块内存区域。——项目之中尽量使用结构体,而不要单独使用数组。
2、结构体的声明与定义
规范:
(1)如果此结构体在多个文件中使用就放在头文件中(.h文件中);如果此结构体只在本文件中使用,则放在源文件中(.c文件中),并加以static限定。
(2)如果是用typedef起别名,则以_t作为后缀;如果是用static限定的则不用_t后缀。
typedef __packed struct
{
uint8_t datetime[6]; // 年月日,时分秒 (BCD) -- 连续驾驶开始/结束时间
int16_t altitude; // 海拔
int32_t longitude; // 经度
int32_t latitude; // 纬度
} gbt19056_fatigue_info_t;// __packed表示一字节对齐,单片机编程中常用
// gbt19056_fatigue_info_t相当于类型名,类似于int,float之类的
static struct
{
rtc_timer_t timer_check;
uint16_t attr; // 区域属性
ca8gps_event_data_t event;
} t808_area;
结构体声明的时候一定要注意字节对齐的问题,加上__packed为了一字节对齐,否则默认是4字节对齐的。
定义和声明:定义分配内存,声明不分配内存。
3、结构体的初始化接口
规范:函数名大写的是对外接口,函数名全小写加下划线的是对内接口。
typedef重命名的要先定义一个变量,然后再使用,如下:
gbt19056_fatigue_info_t info1; // 访问则是info1.altitude = 0x012;
gbt19056_fatigue_info_t *info2; // 访问则是info2->altitude = 0x012;
static限定的则直接使用,t808_area. attr = 0x55;
一般项目中要写初始化函数:
void gbt19056_fatigue_init(void)
{
memset(&info, 0, sizeof(gbt19056_fatigue_info_t));
memcpy(info2->datetime, date, sizeof(info2->datetime));
info2->altitude = 0;
info2->longitude = 0x7FFFFFFF;
info2->latitude = 0x7FFFFFFF;
}
4、结构体访问接口
比较大型一点的项目之中,多个文件会用到一些结构中的成员,因此写成接口形式。
规范:一般少使用全局变量,需要某些值的时候以函数接口形式给予。
uint16_t T808AreaAddr(void)
{
return t808_area. attr;
}
void GBT19056FatigueTime(char *data)
{
memcpy(data, info2->datetime, sizeof(info2->datetime));
}
5、结构体中一些技巧
处理批量类似事情:
// 一个命令字对应一个处理函数,用for循环扫描
// 命令字有的用枚举, 有的用宏
typedef enum
{
T808_CUSTOM_CAMERA_COUNT = 1,
T808_CUSTOM_DISTANCE_TYPE = 2,
T808_CUSTOM_OIL = 3,
T808_CUSTOM_VERSION = 4
} t808_t;
// 再三强调,起别名的类型一定要加_t后缀以示区分
typedef uint8_t (*handler_t)(char *data, uint8_t length);
typedef struct
{
// 变量类型和函数参数随机应变
uint8_t cmd;
uint8_t length;
handler_t hander;
} t808_custom_entry_t ;
static uint8_t t808_custom_camera_count(char *data, uint8_t length);
static uint8_t t808_custom_disdance _type(char *data, uint8_t length);
static uint8_t t808_custom_oil(char *data, uint8_t length);
static uint8_t t808_custom_version(char *data, uint8_t length);
//===========================================================
// 定义好结构之后,用数组装载整个命令及其处理函数
static const t808_custom_entry_t t808_custom_entries[] =
{
{T808_CUSTOM_CAMERA_COUNT, 1, t808_custom_camera_count},
{T808_CUSTOM_DISTANCE_TYPE, 1, t808_custom_disdance _type},
{T808_CUSTOM_OIL, 22, t808_custom_oil},
{T808_CUSTOM_VERSION, 14, t808_custom_version},
};
// 在一个函数中用for循环扫描
static void
custom_setting(client_t*client, t808_hdr_t *request, uint16_t length)
{
t808_custom_entry_t*entry;
for(entry = t808_custom_entries; entry->handler; ++entry)
{
if(entry->cmd == request->cmd)
{
entry->handler(data, length); // 只是一个轮廓,仅供参考
break;
}
}
}