blavy 发表于 2014-9-29 17:00:50

结构体与联合体

最近接手了别人做的一个项目,问题不少。
在阅读程序的过程中看到其变量定义上的做法很是让我费解,也让我很郁闷。
他的做法如下,是在联合体里嵌套了多个结构体:

typedefunion_RUN_PARAM{
        unsigned char         array;       
        struct
        {
                unsigned char         name;                                // 0                       
                unsigned char         run_status;                        // 1
                unsigned char         wash_pos;
                unsigned char         solvent_num;
                unsigned char         spe_num;                        //4// 4
                unsigned long                 count;                                // 5
                unsigned int                 atuo_wash;
                unsigned int                 speed_last;
                unsigned int                 second;
                unsigned int                 speed;
                unsigned long                 recycle;       
        }path_sol;
        struct
        {
                unsigned char         name;                                // 0                       
                unsigned char         run_status;                        // 1
                unsigned char         wash_pos;
                unsigned char         back_num;
                unsigned char         spe_num;                        //4// 4
                unsigned long                 count;                                // 5
                unsigned int                 speed_push;
                unsigned int                 count_push;
                unsigned int                 second_push;
                unsigned int                 speed;
                unsigned long                 recycle;       
        }path_sam;
        struct
        {
                unsigned char         name;                                // 0
                unsigned char         run_status;                        // 1
                unsigned int                 temperature;
                unsigned char                spe_num;                        //4// 4
                unsigned long                 count;                                // 5
                unsigned long                 times;
                unsigned int                 second;
                unsigned int                 speed;
                unsigned long                 recycle;
        }path_other;
}run_param;

而据我用过的新唐单片机里的写法刚好跟他相反,是结构体里嵌套联合体。
众所周知,union模型是共用一段内存,如果是里面再嵌套了struct,那在后续变量操作时难免会互相修改,从而增加产生BUG的机率。
我不知道这个人这样做的目的何在,可能是为了省内存(因为公司想要马儿跑又要马儿不吃草,用资源很少的单片机来做太多的事),但是会想到省内存的人
不会不考虑到互相更改的可能。也许这样的写法有其巨大的好处但我确实看不出来,因为我也是遇到问题才去研究。
当然若有论坛牛人经过也请放缓脚步,为我这种新手普及一下知识。
此只是发发唠骚,不喜勿喷。

blavy 发表于 2014-11-5 22:30:56

本帖最后由 blavy 于 2014-11-5 22:37 编辑

最近学习到一个联合体的好用的方法,可以把几个不在同一个PORT口的引脚结合起来,比如PA1,PB1,PC1,PD1,可以把这几个脚放到一个字节里面用,详细如下:
typedef union       
{
        uint8_t byte;
        struct
        {
                uint8_t B0:1;
                uint8_t B1:1;
                uint8_t B2:1;
                uint8_t B3:1;
                uint8_t B4:1;
                uint8_t B5:1;
                uint8_t B6:1;
                uint8_t B7:1;
        }BITS;
}BYTE_T;
先定义一个联合体分位定义的,这样里面的结构体就和byte共享同一段内存。
void DATA_RESOLVE (uint8_t DATAS)
{
        BYTE_T BUFF;
        BUFF.byte = DATAS;
        PA1 = BUFF.BITS.B0;
        PB1 = BUFF.BITS.B1;
      PC1 = BUFF.BITS.B2;
        PD1 = BUFF.BITS.B3;
//        =BUFF.BITS.B4;
//        =BUFF.BITS.B5;
//        =BUFF.BITS.B6;
//        =BUFF.BITS.B7;
}
这样一来,如果你想要四个脚输出PA1=1,PB1=0,PC1=0,PD2=0;只要用一条调用语句 DATA_RESOLVE (0x01);即可,可以把分散的引脚整合到一起,象一个PORT口里的一样。{:lol:}

CaineStrong 发表于 2014-12-2 17:10:28

对于位的声明,要注意对齐。
之前这样定义
union mSol
{
struct
{
unsigned mSOL_Pos_L:    12;
unsigned mSOL_Feh_L:      2;
unsigned mSOL_Ref_L:       2;
unsigned reserved:             8;
unsigned mSOL_Pos_R:   12;
unsigned mSOL_Feh_R:      2;
unsigned mSOL_Ref_R:       2;
}name;
unsigned char byte;
};
出现数据丢失。
才发现是对齐问题,改为下面的就好啦。惭愧惭愧。
union mSol
{
struct
{
unsigned mSOL_Pos_L_L:    8;
unsigned mSOL_Pos_L_H:   4;
unsigned mSOL_Feh_L:      2;
unsigned mSOL_Ref_L:       2;

unsigned reserved:             8;
unsigned mSOL_Pos_R_L:   8;

unsigned mSOL_Pos_R_H:4;
unsigned mSOL_Feh_R:      2;
unsigned mSOL_Ref_R:       2;
unsigned reserved:             8;
}name;
unsigned char byte;
};

czg1411 发表于 2014-9-29 17:17:59

省内存,可共享使用也可交替使用

carolxr 发表于 2014-9-29 17:21:14

这种用法很常见啊。
unsigned char   array定义了一个char类型的数组,长度是21,后面的几个结构体都是跟这个数组共享同一个数据空间。
或者这么说,这段程序定义了一段内存空间,使用union结构体可以有多种方式去访问这段内存。你可以使用数组方式去访问,比如要对这段内存初始化清零的时候,使用数组就方便多了。同样的,如果你只需要访问内存中的某个字段,就用结构体的方式。定义多个结构体,可能是因为不同的对象,其属性不完全相同。
不好意思,说的不是很清楚。
单片机编程,本来就是要考虑节省内存,在哪里都一样,嵌入式编程就是这样,不比计算机编程,想怎么样就怎么样。

danielyuan 发表于 2014-9-29 17:22:43

carolxr 发表于 2014-9-29 17:21
这种用法很常见啊。
unsigned char   array定义了一个char类型的数组,长度是21,后面的几个结构体都是 ...

正解,这样写,对内存操作很灵活

javenreal 发表于 2014-9-29 17:34:27

他这个联合体定义了4个东西(一个数组+三个结构体),这样只是为了方便存取,并不是想拿这一份内存保持4份内容,实际也是不可能的。

hemingjing 发表于 2014-9-29 18:04:13

学习了。。

naiqiqnus 发表于 2014-9-29 18:10:37

围观………………{:smile:}

hover_007 发表于 2014-9-29 18:14:20

围观………………

acc444444 发表于 2014-9-29 19:33:29

围观......看不懂

security 发表于 2014-9-29 19:33:57

carolxr 发表于 2014-9-29 17:21
这种用法很常见啊。
unsigned char   array定义了一个char类型的数组,长度是21,后面的几个结构体都是 ...

好处就是带来这种灵活方便的处理,但命名最好采用类似匈牙利命名,成员命名要注意用户体验,让人单看变量名称,就知道这是联合体。。。否则,这种写法,还不如直接取结构体的指针操作直观。

TANK99 发表于 2014-9-29 19:58:42

这种定义方式就是为了操作方便,多个复用同一个内存段(联合)就是为了省内存。
选用不同的结构体名,是为了在不同的代码进行区分,如全用一个变量名,有人会晕。

单片机中运行的读取操作,数据如果是字节数组形式的会比较方便,可以编写一些通用的函数来处理,为自己偷懒。

blavy 发表于 2014-9-29 20:50:59

carolxr 发表于 2014-9-29 17:21
这种用法很常见啊。
unsigned char   array定义了一个char类型的数组,长度是21,后面的几个结构体都是 ...

那使用union时除了需要注意串值还需要关注一些什么事项,因为现在这个项目很容易运行出错。不得不把可能的地方都考虑到

blavy 发表于 2014-9-29 20:52:12

TANK99 发表于 2014-9-29 19:58
这种定义方式就是为了操作方便,多个复用同一个内存段(联合)就是为了省内存。
选用不同的结构体名,是为了 ...

学习了,查查相关资料看看

lqs123 发表于 2014-9-29 21:35:56

围观,学习

yiminglei_2 发表于 2014-9-29 21:41:44

学习~~~~~~

zl_123 发表于 2014-9-29 21:55:43

很详细,谢谢                     

whatcanitbe 发表于 2014-9-29 22:49:57

这肯定是个高手写的代码。

touch_mcu 发表于 2014-9-29 23:02:45


围观。。。。。。
结构体,联合体,数组应还有更强大的组合,求高手普及知识。。。。

gonboy 发表于 2014-9-30 08:46:45

结构长度一致。就OK

gushuailove 发表于 2014-9-30 09:02:28

闲下来优化的时候这样可以,赶进度的时候不见得好用,还是老实的传递指针比较明白。

hnac_ddh 发表于 2014-9-30 09:06:26

数据结构的优化,不仅仅是省内存这一点好处,有时候对算法效率的提升不是一点两点.

makathy 发表于 2014-9-30 09:10:28

方便程序设计,尤其在数据处理比较多的时候,效率很高;经常用

ahong2hao 发表于 2014-9-30 09:13:37

对不同属性的多个变量同时操作时,就很方便了。比用指针直观。且很方便进行数据的增减。
比如把上面结构内的数据存入FLASH或从FLASH读出来的时候,对数组操作,在通过结构提取。

arm_m0 发表于 2014-9-30 09:16:04

这样写,定义时虽然麻烦了点,但是程序中在使用,是非常方便的。飞思卡尔MCU的寄存器头文件,好像也都是这样写的,

swap2013 发表于 2014-9-30 09:24:03

省内存,数据存取效率高,
隐含数据处理,比如8bit位移操作。有些32bit/64bit数据声明时都弄成联合。

机器人天空 发表于 2014-9-30 09:26:56

{:titter:}高手都这么写

chengz 发表于 2014-9-30 09:43:35

几个结构体共享内存,没什么问题,比如同一内存可按整数操作和按字节操作,基本用法

kingqb 发表于 2014-9-30 09:47:18

高手的代码,对数据操作灵活。

Joezhu 发表于 2014-9-30 09:50:02

这样写转换时比较清晰方便

elecboy 发表于 2014-9-30 09:57:43

好处多多啊,比如用于flash 存储,串口数据发送。

lovecxm 发表于 2014-9-30 12:42:10

TANK99 发表于 2014-9-29 19:58
这种定义方式就是为了操作方便,多个复用同一个内存段(联合)就是为了省内存。
选用不同的结构体名,是为了 ...

同意此观点

yzl0208994 发表于 2014-9-30 12:54:08

方便操作,他估计也会交叉着用,直接强制转换来引用

luohui5003 发表于 2014-9-30 16:47:19

学习了,顶一个!

dz46316740 发表于 2014-9-30 17:50:43

3楼正解,解析包的时候就知道它的好处了

blavy 发表于 2014-11-3 23:19:40

carolxr 发表于 2014-9-29 17:21
这种用法很常见啊。
unsigned char   array定义了一个char类型的数组,长度是21,后面的几个结构体都是 ...

{:victory:}现在也意识到这个方法的好处了。
简单通信时候用这个方法整合一条协议,操作起来很方便。

zyw19987 发表于 2014-11-4 07:50:40

一直这样用
要注意的是使用一些库函数操作字符串的时候结尾没有结束符,所以定义时应比你最大长度还要大一个。这个问题值得你注意。

proc 发表于 2014-11-4 08:12:08

这种用法很灵活啊。

朝闻夕道 发表于 2014-11-4 08:28:04

好处不要太多啊;

多用结构体,尤其是和联合体一起用,多用函数指针, 这样C水平才能前进一步啊;

mdd 发表于 2014-11-4 09:27:20

看到不懂的进来学习一下

重庆酱油仔 发表于 2014-11-4 09:39:34

用的时候就知道了,如果只是数组就麻烦大了,每次都记身份证号的难度,大于记名字啊。

jqbkl007 发表于 2014-11-4 13:41:48

学习了!

lingergz 发表于 2014-11-5 13:23:07

从没用过这么高深的东东啊

armku 发表于 2014-11-5 20:24:38

IAR一些头文件好像是这么写的。

tang2006 发表于 2014-11-5 21:46:02

多谢楼主分享

blavy 发表于 2014-11-5 22:17:03

最近学习到一个

ycping 发表于 2014-11-5 22:40:53

学习,我也是这么用。最常用的就是AD,不用左移右移的

blavy 发表于 2014-11-5 22:52:09

本帖最后由 blavy 于 2014-11-5 22:53 编辑

ycping 发表于 2014-11-5 22:40
学习,我也是这么用。最常用的就是AD,不用左移右移的

我是用来做按键扫描
void Key_Read()                        
{
        uint8_t ReadData;
        press_time = 0x3fe;
        ReadData =~ keyconvert();
        while(--press_time)
                  Trg = ReadData & (ReadData ^ Cont);       
        Cont = ReadData;
}

uint8_t keyconvert()        
{       
        uint8_t Key_num;
        PORT portkey;
        portkey.BITS.B0 = KEY1;
        portkey.BITS.B1 = KEY2;
        portkey.BITS.B2 = KEY3;
        portkey.BITS.B3 = 1;
        portkey.BITS.B4 = 1;
        portkey.BITS.B5 = 1;
        portkey.BITS.B6 = 1;
        portkey.BITS.B7 = 1;
        Key_num= portkey.byte;
        return Key_num;
        }
然后用一个switch扫描按键,可做短按长按,非常方便

lylm123 发表于 2014-11-5 23:01:23

进来学习一下,以前从未这样用过。

Gline77 发表于 2014-11-5 23:10:32

carolxr 发表于 2014-9-29 17:21
这种用法很常见啊。
unsigned char   array定义了一个char类型的数组,长度是21,后面的几个结构体都是 ...

正解,面向对象编程

落叶知秋 发表于 2014-11-5 23:21:07

结构体和联合体的相互内嵌,根据不同功能而不同,最近用过结构内嵌联合体的

ApexUSB 发表于 2014-11-7 01:00:51

blavy 发表于 2014-11-5 22:52
我是用来做按键扫描
void Key_Read()                        
{


这样也行呀,我只用它做过浮点数转4个字节byte。

wangyu_2011 发表于 2014-11-7 01:10:57

这个太正常了,有很多这么用的。

撒手归路 发表于 2014-11-7 01:11:15

学习了

wzy016388 发表于 2014-11-7 01:18:33

受教了 感谢指导

mdj-fish 发表于 2014-11-7 01:54:16

受教了 感谢指导

richie550 发表于 2014-11-7 01:57:12

多谢楼主分享!

solid3d 发表于 2014-11-7 06:29:11

省内存的做法,单片机中很常用

hustsolo 发表于 2014-11-7 08:21:48

能读懂,会用,但自己不会主动这么写,怕出问题。。

hustsolo 发表于 2014-11-7 08:27:37

这样写的话,我觉得移植性就不高了,因为联合中array的大小要和path_sol等其他结构体的大小一致,而其他结构体中的int,long等类型的长度在不同机器上是可变的。比如,当int是4个字节的时候,array的定义就要改。

levy 发表于 2014-11-7 08:47:50

学习了,做串口协议的时候,能用上了。。

TrulyZhu 发表于 2014-11-7 08:58:57

不错,记号学习下

xia2816590 发表于 2014-11-7 09:33:40

谢谢 也经常这么用

yao2013lin 发表于 2014-11-7 10:02:01

我也碰到同样一个项目,但是我是先看他写的程序,然后自己慢慢的学着写,现在已经搞定了那个项目

baoya1 发表于 2014-11-7 10:16:10

看来我也要努力考虑内存大小的使用

大号维尼 发表于 2014-11-7 10:30:44

学习学习

tiger2023 发表于 2014-11-7 11:15:44

联合体里面使用结构体 不仅可以节省内存 还能大大提高程序的运行效率

nhztb 发表于 2014-11-17 22:00:31

这个好处很多,可以让很多函数偶合性降低,方便编程。

nhztb 发表于 2014-11-17 22:01:23

很多时候传递参数只用指针就行了,不用各种外部变量了,。

chenzb 发表于 2014-11-18 10:37:01

能真正用好,好处多多。

贪吃的蚂蚁 发表于 2014-11-18 11:39:05

受教了,从没想过这么用呢

newuseruser 发表于 2014-11-18 14:16:23

baoya1 发表于 2014-11-7 10:16
看来我也要努力考虑内存大小的使用

这可不是为了节约内存哦,是为了方便操作。

second_chan 发表于 2014-11-18 14:19:55

围观。。。表示没用过

ggchao 发表于 2014-11-18 14:36:02

首先用一个数组也能实现相同的功能,但是使用数组就涉及到以后升级的话,改动会很大,因为可能很多index都要修改,而且这里面还用了不同的变量类型(unsigned long, unsigned char, unsigned int)更加难以控制;再有使用结构体的好处嘛,取成员操作方便,实现通信协议或类似的软件不容易出错。个人见解而已。

rockyyangyang 发表于 2014-11-18 14:51:43

这种方法真是很好用,不是为了节省内存,为了方便数的操作,至少你可以用这样的方法来代替之前的左移右移!计算更快!{:victory:}{:victory:}

zhdiamond 发表于 2014-11-18 15:02:51

学习了!受教~!

太极风436 发表于 2014-11-18 15:10:06

学习了,,,,

myh_hh 发表于 2014-11-18 23:07:04

mark学习了

JnzGoto 发表于 2014-11-18 23:27:05

长知识了,好写法!

995971182 发表于 2014-11-24 16:20:54

围观.学习

xiaozuowei118 发表于 2014-12-1 20:16:49

这种方法不错,学习了,操作太方便了,

CaineStrong 发表于 2014-12-2 16:52:42

要注意对齐问题!
我原来定义的时候,没有注意对齐问题,结果有数据丢失。查了半天{:cry:}

hxhz123456 发表于 2014-12-2 16:54:56

这种定义舍内存,也好区分,增加程序的可读性啊.

wangkx1990 发表于 2014-12-2 17:22:40

hustsolo 发表于 2014-11-7 08:27
这样写的话,我觉得移植性就不高了,因为联合中array的大小要和path_sol等其他结构体的大小一致,而其他结 ...

所以又提现了一个stdint.h的重要性

zwhzwh_11 发表于 2014-12-2 17:32:30

mark,键盘扫描可以用得上

blavy 发表于 2014-12-2 19:21:39

CaineStrong 发表于 2014-12-2 17:10
对于位的声明,要注意对齐。
之前这样定义
union mSol


{:handshake:} 对,后面有改掉了,这样还能更省内存,把那些用于补齐的空间也利用起来。

dmzy 发表于 2014-12-2 19:25:28

这个必须MARK啊,一直有这样的想法,但是不知道怎么弄,看到这个贴的回复恍然大悟啊

bumianren123 发表于 2014-12-3 10:35:41

这样做的好处主要是方便数据操作,譬如牵涉到数据类型转换的时候,太方便了。

hantnt 发表于 2014-12-8 09:29:41

看到楼主可耻的头像,我可耻的硬了。

tbcrv 发表于 2014-12-8 19:14:26

对于结构体,联合体什么的一直很头痛,现在也没闹明白。

7nian 发表于 2014-12-8 19:25:08

学习了,这样处理数据缺失很方便

unnormal 发表于 2014-12-27 09:08:34

分场合   每一种设计思路都会有它的优点和缺点   要学会借鉴灵活运用才是最好的
页: [1]
查看完整版本: 结构体与联合体