OpenEdv-开源电子网

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

关于C语言结构体的小问题

[复制链接]

2

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2017-8-4
在线时间
3 小时
发表于 2018-2-2 09:36:16 | 显示全部楼层 |阅读模式
1金钱
结构体在使用其某成员变量时用:
结构体名.结构体成员     方式

忽然想到   GPIOA->ODR   这个结构,隐约记得这个和指针有关,这个结构具体是啥意思来着,和引用结构体成员变量的方式有什么区别?

最佳答案

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

为了彻底弄清这个问题,让我们来看看下面的问题 如下两个表达式,怎样去计算它的结果? 它的结果到底是什么? (1)结构体变量.成员变量 (2)结构体变量指针->成员变量 首先要明白(1)中的结果是一个变量值,类似 int a 一样,都是变量; (2)中的结果是一个指针指向的值,跟普通的 *(int *a) 也一样,最终结果是变量。 对编译器来说,要知道一个变量的值,必须先找到它的地址,再确定该变量的类型, 知道了类型, ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

44

主题

224

帖子

0

精华

高级会员

Rank: 4

积分
627
金钱
627
注册时间
2013-11-22
在线时间
127 小时
发表于 2018-2-2 09:36:17 | 显示全部楼层
本帖最后由 zhp 于 2018-2-2 14:44 编辑

为了彻底弄清这个问题,让我们来看看下面的问题
如下两个表达式,怎样去计算它的结果?
它的结果到底是什么?
(1)结构体变量.成员变量
(2)结构体变量指针->成员变量


首先要明白(1)中的结果是一个变量值,类似 int a 一样,都是变量;
(2)中的结果是一个指针指向的值,跟普通的 *(int *a) 也一样,最终结果是变量。
对编译器来说,要知道一个变量的值,必须先找到它的地址,再确定该变量的类型,
知道了类型,自然就知道数据的字节长度了;而要知道一个指针,就是找到它的地址
即可,这时候的地址即可理解为指针,通过指针指向的地址去找它所存储的变量。



在(1)中的结果是个变量:
要确定它的值,就得先确定它的地址,再确定它的变量类型(即数据占用的字节长度)
它的地址 = 结构体变量首地址 + 成员变量在结构体中的偏移地址
它的类型 = 成员变量前面的类型修饰符
至于成员变量的类型也可为普通类型,比如 int, short, char 等,甚至它也可以为结构体
类型、联合类型、枚举类型等。


在(2)中的结果是个指针(即地址)指向的变量:
只要确定出它的地址即可
它的地址 = 结构体变量首地址 + 成员变量在结构体中的偏移地址它的类型 = 成员变量前面的类型修饰符
它的结果就有点类似于:*(地址)
对地址取* ,结果是变量
在某些代码中,你甚至可以看到以下这样的表达:


(3)( (结构体类型 *)0 )->成员变量


这是什么意思呢?它的计算结果是一个地址?!对,它是个地址
将0地址强制转换成一个结构体类型,通过结构体类型就可以访问结构体
内部的成员变量,说它是一个地址,那么它的地址是多少呢?
(3)的地址 = 0 + 成员变量在结构体中的偏移地址
                    = 成员变量在结构体中的偏移地址
通过上面的计算,可以看出(3)的结果是一个地址,它的大小刚好等于成员变量
在结构体中的偏移地址,所以(3)这种表达式也有一个特殊用途,就是用
来计算一个结构体成员在结构体中的字节偏移量,所以也可以把它当做一个
变量来使用。


接着分析:
#define PERIPH_BASE          ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */
#define APB2PERIPH_BASE      (PERIPH_BASE + 0x10000)
#define GPIOA_BASE            (APB2PERIPH_BASE + 0x0800)
#define GPIOA              ((GPIO_TypeDef *) GPIOA_BASE)
typedef struct
{
  __IO uint32_t CRL;
  __IO uint32_t CRH;
  __IO uint32_t IDR;
  __IO uint32_t ODR;
  __IO uint32_t BSRR;
  __IO uint32_t BRR;
  __IO uint32_t LCKR;
} GPIO_TypeDef;
GPIOA_BASE =0x40000000 + 0x10000 + 0x0800 = (uint32_t) 0x40010800
GPIOA->ODR = ( (GPIO_TypeDef *)0x40010800) ->ODR
                     = *(0x40010800 + 4*3)
                     = *(0x40010800 + 12)
                     = *(
(GPIO_TypeDef *)0x4001080C)
好,我们来查看STM32F10X的数据手册,查看存储器映像来核对一下 0x4001080C 这个地址
1.png
file:///C:/Users/Administrator/Documents/My%20Knowledge/temp/523943fc-1ee0-42ef-b893-70e450d0dbe6/128/index_files/ad3edc74-58d7-4a84-92ab-bf9ee189544b.png
可以看出GPIO端口A的基地址为:0x40010800
再看ODR在结构体内的偏移地址
2.png
file:///C:/Users/Administrator/Documents/My%20Knowledge/temp/523943fc-1ee0-42ef-b893-70e450d0dbe6/128/index_files/d206c303-06b4-4027-a561-202fe00b65b3.png
可以看出GPIOx_ODR的偏移为:00CH     (x是统称,可以是A,B,C,D,E,F,G)
那么 从手册中,我们可以看出 GPIOA->ODR 最终地址为:0x40010800 + 00ch = 0x4001080C
跟前面的宏展开计算结果一致!那么
GPIOA->ODR = VAL;
就等效于
(*(volatile uint32_t*)(0x4001080C)) = VAL;








回复

使用道具 举报

0

主题

192

帖子

0

精华

高级会员

Rank: 4

积分
580
金钱
580
注册时间
2017-6-2
在线时间
192 小时
发表于 2018-2-2 09:57:56 | 显示全部楼层
把结构体看做一个特定类型的变量,如果这个变量是实体的,就用点,如果是指针就用箭头
回复

使用道具 举报

56

主题

342

帖子

0

精华

高级会员

Rank: 4

积分
965
金钱
965
注册时间
2016-3-8
在线时间
265 小时
发表于 2018-2-2 11:16:25 | 显示全部楼层
struct AAA {
    int a;
    char b;
};
struct AAA q; 访问成员就用:q.a;
struct AAA *p; 访问成员就用:p->a;
回复

使用道具 举报

2

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2017-8-4
在线时间
3 小时
 楼主| 发表于 2018-2-2 15:01:04 | 显示全部楼层
jkd405 发表于 2018-2-2 09:57
把结构体看做一个特定类型的变量,如果这个变量是实体的,就用点,如果是指针就用箭头

明白了,谢谢啦
回复

使用道具 举报

2

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
50
金钱
50
注册时间
2017-8-4
在线时间
3 小时
 楼主| 发表于 2018-2-2 15:01:46 | 显示全部楼层
pdwdzz 发表于 2018-2-2 11:16
struct AAA {
    int a;
    char b;

嗯嗯,我记得是和指针有关来着,谢啦
回复

使用道具 举报

8

主题

89

帖子

0

精华

高级会员

Rank: 4

积分
686
金钱
686
注册时间
2017-8-8
在线时间
494 小时
发表于 2018-2-2 18:01:12 | 显示全部楼层
pdwdzz 发表于 2018-2-2 11:16
struct AAA {
    int a;
    char b;

p->a等价于(*p).a
回复

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
4
金钱
4
注册时间
2018-6-23
在线时间
0 小时
发表于 2018-8-28 21:59:57 | 显示全部楼层
正好在了解这方面的知识
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-6-16 18:23

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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