OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 9503|回复: 14

关于结构体数据在stm32f103中的存放方式和对齐方式。

[复制链接]

1

主题

8

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2015-10-21
在线时间
3 小时
发表于 2016-3-5 11:07:34 | 显示全部楼层 |阅读模式
10金钱
[img]file:///C:\Documents and Settings\Administrator\Application Data\Tencent\Users\516880916\QQ\WinTemp\RichOle\OE7XQ[}UK9H3_CBI$YTJ~CL.png[/img]结构体如下所示,
typedef union int16un
{
uint8_t b[2];
int16_t val;
}int16_un;

typedef union int32un
{
uint8_t b[4];
int32_t val;
}int32_un;

typedef struct HawkerPacket_tt
{
uint8_t header[2];
uint8_t cmd;
uint8_t len;
       
int16_un roll;
int16_un pitch;
int16_un yaw;
int32_un alti;
int16_un temp;
int32_un pres;
int16_un speed;
uint8_t sum;
}HawkerPacket_t;


初始化为
        up.header[0]=0xAA;
        up.header[1]=0xAA;
        up.cmd=1;
        up.len=18;
        up.roll.val= 12;
        up.pitch.val= 25;
        up.yaw.val= 37;
        up.alti.val=43;               
        up.temp.val=52;
        up.pres.val=67;
        up.speed.val=74;
由于要用串口发送结构体中的数据给上位机,所以有发送代码(up为HawkerPacket_t结构体):
                        for(i=0;i<10;i++)               
                                sendPCBuf=*((uint8_t *)(&up) + i);
                        for(i=10;i<16;i++)
                                sendPCBuf=*((uint8_t *)(&up) + 2+i);  (为什么要加2)
                        for(i=16;i<23;i++)
                                sendPCBuf=*((uint8_t *)(&up) + 4+i);  (为什么要加4)

最后输出结构体变量地址,8位的发:
&sendPC[0] = 536871188                  +28地址
&sendPC[1] = 536871216                  +28
&sendPC[2] = 536871244                  +28
&sendPC[3] = 536871272                  +28
&sendPC[4] = 536871300                  +28
&sendPC[5] = 536871328                  +28
&sendPC[6] = 536871356                  +28
&sendPC[7] = 536871384                  +28
&sendPC[8] = 536871412                  +28
&sendPC[9] = 536871440                   +84 地址

&sendPC[10] = 536871524                 +28
&sendPC[11] = 536871552                 +28
&sendPC[12] = 536871580                 +28
&sendPC[13] = 536871608                 +28
&sendPC[14] = 536871636                 +28
&sendPC[15] = 536871664                  +84地址

&sendPC[16] = 536871748                 +28
&sendPC[17] = 536871776                 +28
&sendPC[18] = 536871804                 +28
&sendPC[19] = 536871832                 +28
&sendPC[20] = 536871860                +28
&sendPC[21] = 536871888                 +28
&sendPC[22] = 536871916
为什么输出的地址相差28????????????????????还有相差84??
但是打印输出数据又没错,如下所示:

sendPC[0] = 170   (header[0])
sendPC[1] = 170   (header[1])
sendPC[2] = 1     (cmd)
sendPC[3] = 18    (len)
sendPC[4] = 0
sendPC[5] = 12    (roll)
sendPC[6] = 0
sendPC[7] = 25    (pitch)
sendPC[8] = 0
sendPC[9] = 37     (yaw)
sendPC[10] = 0
sendPC[11] = 0
sendPC[12] = 0
sendPC[13] = 43    (alti)
sendPC[14] = 0
sendPC[15] = 52    (temp)
sendPC[16] = 0
sendPC[17] = 0
sendPC[18] = 0
sendPC[19] = 67     (pres)
sendPC[20] = 0
sendPC[21] = 74     (speed)
sendPC[22] = 0


有同仁能指点下么?钱不够,望笑纳



最佳答案

查看完整内容[请看2#楼]

我算明白你这代码是啥意思了,写的不伦不类的, 我看到你上面的代码,了解到up的地址为536871188(我们都是用十六进制的,0x20000114) i = 9时,(&up) + i) = 0x20000114 + 9*sizeof(up) ,也就是你打印出的&sendPC[9] = 536871440那一行 i = 10时,(&up) + i+2) = 0x20000114 + (10+2)*sizeof(up) ,也就是你打印出的&sendPC[10] = 536871524那一行 所以前后差值为3*sizeof(up) =84确凿无误,前文已经解释了。 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

6

主题

1097

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3571
金钱
3571
注册时间
2014-12-2
在线时间
365 小时
发表于 2016-3-5 11:07:35 | 显示全部楼层
XZFZ 发表于 2016-3-5 17:23
sendPC就是sendPCBuf,一下为其类型:
static uint8_t sendPCBuf[64]={0xAA,0xAA,0x01,0x14,0,100,0,200 ...

我算明白你这代码是啥意思了,写的不伦不类的,


我看到你上面的代码,了解到up的地址为536871188(我们都是用十六进制的,0x20000114)

i = 9时,(&up) + i) = 0x20000114 + 9*sizeof(up) ,也就是你打印出的&sendPC[9] = 536871440那一行

i = 10时,(&up) + i+2) = 0x20000114 + (10+2)*sizeof(up) ,也就是你打印出的&sendPC[10] = 536871524那一行

所以前后差值为3*sizeof(up) =84确凿无误,前文已经解释了。

我明白楼主是什么意思,诚然,其结构体默认的4字节对齐会导致结构体内和结构体之间不紧凑,但我们使用结构体通常是使用“.”便列出成员没什么问题,只有在将结构体当成数据包发送出去的时候才需要考虑把那些编译器保留的为了对齐的单元跳过不发(你代码中+2,+4就是源于此),这一点只需要翻开C语言的基础就可以获得答案
坚决不用寄存器,拒绝重复造轮子。
回复

使用道具 举报

6

主题

1097

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3571
金钱
3571
注册时间
2014-12-2
在线时间
365 小时
发表于 2016-3-5 14:08:01 | 显示全部楼层
首先,结构体的存储方式和对齐方式是由编译器确定的,与STM32无关,

默认是四字节对齐,包括结构体内的成员和结构体的size,详解:
[mw_shl_code=c,true]typedef struct HawkerPacket_tt
{
    uint8_t header[2];      // 2   
    uint8_t cmd;            // 1
    uint8_t len;            // 1
        
    int16_un roll;          // 2
    int16_un pitch;         // 2
    int16_un yaw;           // 2
    /* 下一个是32位数据要四字节对齐 */
    /* 此处会预留 2 字节 */
    int32_un alti;          // 4
    int16_un temp;          // 2
    /* 下一个是32位数据要四字节对齐 */
    /* 此处会预留 2 字节 */
    int32_un pres;          // 4
    int16_un speed;         // 2
    uint8_t sum;            1
    /* 整个结构体要四字节对齐 */
    /* 此处会补充 1 字节 */
} HawkerPacket_t;[/mw_shl_code]
这个结构体的size是28。

这样就很容易解释为什么串口发送时要+2,+4了,那是为了越过编译器保留的两处2字节保留空间


如果sendPC的类型是(HawkerPacket_t *)的话,
那么(&sendPC[k+1] - &sendPC[k])恒为28(即sizeof(HawkerPacket_t )),你给的数据9-10之间竟差84,这我表示怀疑。


但是你又给出“sendPC[0] = 170”这样的语句,究竟是何意?sendPC究竟是什么类型???




坚决不用寄存器,拒绝重复造轮子。
回复

使用道具 举报

69

主题

978

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3772
金钱
3772
注册时间
2015-4-26
在线时间
765 小时
发表于 2016-3-5 16:25:19 | 显示全部楼层
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2015-10-21
在线时间
3 小时
 楼主| 发表于 2016-3-5 17:23:56 | 显示全部楼层
xkwy 发表于 2016-3-5 14:08
首先,结构体的存储方式和对齐方式是由编译器确定的,与STM32无关,

默认是四字节对齐,包括结构体内的 ...

sendPC就是sendPCBuf,一下为其类型:
static uint8_t sendPCBuf[64]={0xAA,0xAA,0x01,0x14,0,100,0,200,0,130,0,0,0,100,0,0,0,200,0,0,0,30,0,10,0x6B};
关于地址差28和84那么多,我也不知道,我就是打印出(&up) + i)、(&up) + 2+i)、(&up) + 4+i)的地址:printf("sendPC[%d]=%d\n",i,(&up) + i));这种语句,另外两个循环分别打印:
           printf("sendPC[%d]=%d\n",i,((&up) + i+2))和 printf("sendPC[%d]=%d\n",i,((&up) + i+4)).
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2015-10-21
在线时间
3 小时
 楼主| 发表于 2016-3-5 17:31:07 | 显示全部楼层
来俩不甜的 发表于 2016-3-5 16:25
http://www.openedv.com/forum.php?mod=viewthread&tid=27512  拿走,不谢

如果说我们的数据存储在内存中的位置跟地址有关,比如一个long型变量,由于地址1244973~1244975中都没有能被4(因为sizeof(long)=4bytes)整除的,那么就得继续放到1244976地址,1244976能被4整除,所以long应该放在1244976处。          这样说的话,我们的数据存的位置还跟起始放置的位置有关,那么,我们在设置结构体的时候,我们又不知道结构体被放到那个起始地址,这样的话,我们要取数据出来,那不得先把每一个数据的地址输出,然后根据具体地址取出数据吗?????请赐教。谢谢
回复

使用道具 举报

69

主题

978

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3772
金钱
3772
注册时间
2015-4-26
在线时间
765 小时
发表于 2016-3-6 13:22:26 | 显示全部楼层
XZFZ 发表于 2016-3-5 17:31
如果说我们的数据存储在内存中的位置跟地址有关,比如一个long型变量,由于地址1244973~1244975中都没有 ...

你怎么拿全局变量运算的,有必要知道地址吗? a.b不就是你要的值吗
我有故事,你有酒吗
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2015-10-21
在线时间
3 小时
 楼主| 发表于 2016-3-6 14:15:30 | 显示全部楼层
xkwy 发表于 2016-3-5 20:17
我算明白你这代码是啥意思了,写的不伦不类的,

i= 9时,(&up) + i) = 0x20000114 + 9*sizeof(up) ,也就是你打印出的&sendPC[9] = 536871440那一行

i = 10时,(&up) + i+2) = 0x20000114 + (10+2)*sizeof(up) ,也就是你打印出的&sendPC[10] = 536871524那一行

你好,你说的这个我还是没能理解,这里i=9时,((&up)+i)不是应该等于0x20000114 + 9么,为什么要乘sizeof(up),    up是结构体呀,地址不是都在结构体范围内吗?乘以sizeof(up)那这地址不就跑出多个结构体大小范围了。。。。不懂,还望指点迷津。。谢谢
回复

使用道具 举报

6

主题

1097

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3571
金钱
3571
注册时间
2014-12-2
在线时间
365 小时
发表于 2016-3-6 14:18:13 | 显示全部楼层
XZFZ 发表于 2016-3-6 14:15
i= 9时,(&up) + i) = 0x20000114 + 9*sizeof(up) ,也就是你打印出的&sendPC[9] = 536871440那一行

i ...

你暴露了,

两个选择:
1、放弃这个问题
2、回去找本C语言基础入门重新学习三个月,尤其是指针和结构体那两章


----分割线-----
恕我不能继续给你解答,因为这在任意一本教材里都能找到答案
坚决不用寄存器,拒绝重复造轮子。
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2015-10-21
在线时间
3 小时
 楼主| 发表于 2016-3-6 14:18:50 | 显示全部楼层
来俩不甜的 发表于 2016-3-6 13:22
你怎么拿全局变量运算的,有必要知道地址吗? a.b不就是你要的值吗

可是我现在用把结构体用串口发送给上位机,而串口只能一个字节一个字节的发,不是应该知道每个地址吗。我知道对齐+2,+4的原因,只是对打印出来的地址相差值28,  84不理解。。
回复

使用道具 举报

6

主题

1097

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3571
金钱
3571
注册时间
2014-12-2
在线时间
365 小时
发表于 2016-3-6 14:20:41 | 显示全部楼层
xkwy 发表于 2016-3-6 14:18
你暴露了,

两个选择:

回去查查,对于一个指针来说“p++”意味着什么、、
坚决不用寄存器,拒绝重复造轮子。
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2015-10-21
在线时间
3 小时
 楼主| 发表于 2016-3-6 14:42:11 | 显示全部楼层
xkwy 发表于 2016-3-6 14:20
回去查查,对于一个指针来说“p++”意味着什么、、

题目是加一个结构体的大小,但是那不是跑出结构体了吗。那变量存在结构体之外么。麻烦解惑。好久没弄C了,兴趣玩四轴才看看的。
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2015-10-21
在线时间
3 小时
 楼主| 发表于 2016-3-6 15:00:33 | 显示全部楼层
xkwy 发表于 2016-3-6 14:20
回去查查,对于一个指针来说“p++”意味着什么、、

哦。我知道了。输出的地址是超出了结构体,而且输出的地址没有错。  实际上这些地址上是没有结构体变量的值的,我开始误以为是有变量也存在这些地址上dizzy:         是我输出地址代码写错了。  应该是 printf("sendPC[%d] addr = %d\r\n",i,((uint8_t *)(&up) + i));要将地址转换成指针类型。
sendPC[1] addr = 536871189
sendPC[2] addr = 536871190
sendPC[3] addr = 536871191
sendPC[4] addr = 536871192
sendPC[5] addr = 536871193
sendPC[6] addr = 536871194
sendPC[7] addr = 536871195
sendPC[8] addr = 536871196
sendPC[9] addr = 536871197
sendPC[10] addr = 536871200
sendPC[11] addr = 536871201
sendPC[12] addr = 536871202
sendPC[13] addr = 536871203
sendPC[14] addr = 536871204
sendPC[15] addr = 536871205
sendPC[16] addr = 536871208
sendPC[17] addr = 536871209
sendPC[18] addr = 536871210
sendPC[19] addr = 536871211
sendPC[20] addr = 536871212
sendPC[21] addr = 536871213
sendPC[22] addr = 536871214
回复

使用道具 举报

69

主题

978

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3772
金钱
3772
注册时间
2015-4-26
在线时间
765 小时
发表于 2016-3-6 17:33:24 | 显示全部楼层
XZFZ 发表于 2016-3-6 14:18
可是我现在用把结构体用串口发送给上位机,而串口只能一个字节一个字节的发,不是应该知道每个地址吗。我 ...

struct _aa
{u8 a,u8 b}aa;
usart_send(aa.a);usart_send(aa.b);
难道有任何问题吗,这不就是发送结构体内容吗
我有故事,你有酒吗
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2015-10-21
在线时间
3 小时
 楼主| 发表于 2016-3-7 09:16:07 | 显示全部楼层
来俩不甜的 发表于 2016-3-6 17:33
struct _aa
{u8 a,u8 b}aa;
usart_send(aa.a);usart_send(aa.b);

可是我结构体中的很多数据不是8位类型,很多是16位的,32位的数据类型,就不能这样了呀。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-20 22:44

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表