【问1】
先构建了一个结构体,里面的screen_illuminate,screen_illuminate_t,*screen_illuminate_pt分别是什么意思,分别有什么用途,为啥要这样写?
typedef struct screen_illuminate
{
uint16_t chn;
uint16_t value;
}screen_illuminate_t, *screen_illuminate_pt;
然后在某一个函数里写一行这个代码:screen_illuminate_t screen_illuminate_chn;
这个的意思是在这个函数里构建一个和screen_illuminate_t一样的,但是名为screen_illuminate_chn的结构体吗?然后就能在screen_illuminate_chn上操作,而不会影响screen_illuminate_t?
【先上自己可能并不严谨,偏应用性的理解】
-
typedef struct screen_illuminate { ... }
: 这是一个结构体定义,名为screen_illuminate
-
screen_illuminate_t
: 别名,类似uint16_t这种写法,比如screen_illuminate_t A;说明你构造了一个
screen_illuminate类型的结构体A,你对A做操作,不会影响
screen_illuminate
-
*screen_illuminate_pt
: 指针别名。screen_illuminate_pt
表示指向screen_illuminate
结构体的指针。比如screen_illuminate_pt A;你对A做操作,是会影响
screen_illuminate的。
【若我有理解错误的地方,请不吝赐教!非常感谢!】
这里引申一个点,关于怎么在其他的函数里操作结构体(希望大家明白且会用)
比如A.h里,你是这样定义protocol结构体的:
//A.h
typedef struct protocol
{
uint8_t cmd;
uint8_t Control_Domain[LAMP_MAX_NUM_define / 8];
}t_protocol, * pt_protocol;
//A.c
t_protocol protocol ;//定义一个protocol结构体类型的实例,取名叫protocol;
void Uart_Handler(pt_protocol protocol)
//这里的protocol是指针,所以下面使用->这个符号去操作protocol
{
update_device_domain(protocol->Control_Domain);
}
然后我在B.h里定义了一个screen结构体,里面我需要包含和protocol这个结构体类型,我取名叫data:
这就分两种情况,
第一种:我想通过操作B.c里screen结构体里的data,直接和A.c一起去控制protocol的值
//B.h
typedef struct screen
{
pt_protocol data;//我想通过操作data,直接改变protocol里的值,所以data是指针
uint16_t page_num;
}t_screen, *pt_screen;
那么B.c里应该怎么写呢?首先你还是把t_protocol protocol思考成和uint8_t aaaa = 0;差不多的东西,aaaa如果要想被其他点c文件的函数用,它就要是一个全局变量,同样的,如果需要protocol变成一个全局的结构体,那么可以在A.h里再写一行:extern t_protocol protocol;
//B.c
t_screen screen;
void Uart_ScreenHandler(pt_screen screen)//我写在BBBB.c里,声明在BBBB.h里
{
screen.data = &protocol;//在函数里写一行
update_device_domain(screen.data->Control_Domain);
}
第二种:我操作B.c里screen结构体里的data,不会影响A.c的protocol的值
//B.h
typedef struct screen//我定义在BBBB.h里
{
t_protocol data2;//我想通过操作data2,不会改变protocol里的值
uint16_t page_num;
}t_screen, *pt_screen;
//B.c
t_screen screen;
void Uart_ScreenHandler(pt_screen screen)//我写在BBBB.c里,声明在BBBB.h里
{
update_device_domain(screen->data.Control_Domain);
}
第一种pt_protocol data1;
data1 是一个指向 t_protocol 结构体的指针,你需要通过 -> 操作符来访问 data 指向的结构体的成员
第二种t_protocol data2;
data2 是 t_protocol 结构体的一个实例,你需要通过.操作符来访问 data2 的成员
总结:
使用 -> 是通过指向结构体或联合体的指针来访问其成员,适用于操作指向结构体或联合体的指针。
使用 . 是直接访问结构体或联合体的成员,适用于操作结构体或联合体的实例。
---------------------------------------------------------------------------------------
【更规范一些的答复】
让我们逐步解释这些概念和代码段的含义和用法。
1. 结构体定义
首先,让我们看一下你提供的结构体定义:
typedef struct screen_illuminate {
uint16_t chn;
uint16_t value;
} screen_illuminate_t, *screen_illuminate_pt;
-
typedef struct screen_illuminate { ... }
: 这是一个结构体定义,名为screen_illuminate
,其中包含两个成员chn
和value
,都是uint16_t
类型。 -
screen_illuminate_t
: 这是一个结构体screen_illuminate
的别名,也就是说,screen_illuminate_t
和struct screen_illuminate
在此处是等价的,可以互换使用。 -
*screen_illuminate_pt
: 这是一个指向screen_illuminate
结构体的指针类型的别名。screen_illuminate_pt
表示指向screen_illuminate
结构体的指针。
所以,这段代码做了两件事:
- 定义了一个结构体
screen_illuminate
,其中有两个成员chn
和value
。 - 创建了两个别名:
screen_illuminate_t
表示结构体screen_illuminate
,screen_illuminate_pt
表示指向结构体screen_illuminate
的指针。
2. 函数内部的变量声明
现在来看你提到的在函数内部的代码:
screen_illuminate_t screen_illuminate_chn;
这行代码的意思是在当前函数内部定义了一个名为 screen_illuminate_chn
的变量,它的类型是 screen_illuminate_t
,也就是之前定义的结构体 screen_illuminate
。
screen_illuminate_t
在这里被用作变量类型,因此screen_illuminate_chn
是一个名为screen_illuminate_t
的结构体变量。
解释和用途
为什么要这样写?
- 代码复用和简化: 使用
typedef
可以简化代码,使得定义结构体和相应的指针更为简洁和可读。 - 清晰的代码结构: 通过
typedef
创建别名,可以使代码更加清晰和易于理解,特别是在涉及多次使用结构体和指针时。 - 避免混淆和错误: 使用
typedef
可以减少因为类型不匹配或错误使用指针而引起的错误。
关于你的问题:在函数内部使用 screen_illuminate_t screen_illuminate_chn;
只是在当前函数的作用域中定义了一个新的结构体变量 screen_illuminate_chn
,它的类型是 screen_illuminate_t
。这不会影响到 screen_illuminate_t
类型的其他变量,因为每个变量都有自己的存储空间和作用域。
总结来说,这种定义方式使得代码更加模块化和可维护,同时确保了变量的类型和指针的正确使用。
【问2】
还有一种是这样用的 ,screen_illuminate_pt screen_illuminate_chn;它和screen_illuminate_t screen_illuminate_chn;的区别是什么?
【答2】
在你提到的这两种声明方式中:
-
screen_illuminate_t screen_illuminate_chn;
这种声明方式直接定义了一个
screen_illuminate_t
类型的结构体变量screen_illuminate_chn
。这意味着screen_illuminate_chn
是一个具体的结构体变量,它占据了实际的存储空间,可以直接访问和操作其成员chn
和value
。screen_illuminate_t screen_illuminate_chn;
screen_illuminate_chn.chn = 1; screen_illuminate_chn.value = 100;
-
screen_illuminate_pt screen_illuminate_chn;
这种声明方式定义了一个指针变量
screen_illuminate_chn
,其类型为screen_illuminate_pt
,即指向screen_illuminate_t
类型的指针。这意味着screen_illuminate_chn
并不直接存储结构体的数据,而是存储结构体的地址,需要通过解引用操作来访问结构体的成员。screen_illuminate_t illuminate_instance; screen_illuminate_pt screen_illuminate_chn = &illuminate_instance; screen_illuminate_chn->chn = 2; screen_illuminate_chn->value = 200;
在这个例子中,
screen_illuminate_chn
是一个指向illuminate_instance
的指针,可以通过->
运算符访问illuminate_instance
的成员。
区别总结:
screen_illuminate_t screen_illuminate_chn;
声明一个结构体变量,直接存储结构体数据。screen_illuminate_pt screen_illuminate_chn;
声明一个结构体指针变量,存储结构体的地址,需要通过解引用来访问结构体成员。
选择使用哪种方式取决于具体的需求和设计。通常情况下:
- 如果你需要直接操作结构体的数据,应该使用
screen_illuminate_t screen_illuminate_chn;
。 - 如果你需要传递结构体的引用或者在函数间共享结构体数据,可以使用
screen_illuminate_pt screen_illuminate_chn;
。
这些声明方式在不同的情况下能提供更灵活和合适的选择。