结构指针及其初始化
Struct pointers and their initialization
我在 C 中有一个结构如下:
typedef struct ENETPACKET_S {
unsigned n_rxcmd, n_txcmd;
uint64_t n_mac; // 8 bytes unsigned or 64 bit
unsigned n_rxmiss, n_rxerr, n_rxcrc, n_txcol;
} ENETPACKET;
正在从下面这个结构的变量定义一个指针:
static volatile ENETPACKET *const _net1 = ((ENETPACKET *)0x00500000);
我有两个问题:
我理解指向结构的指针,但在 _net1
的声明中,定义了来自结构 variable/object 的指针。我不明白。
我对const
指针的((ENETPACKET *)0x00500000)
初始化感到困惑,我不明白这里初始化的是什么以及括号和*
运算符。
看来您正在使用可能带有微控制器的嵌入式设备。在这样的系统中,一些外设可以通过设置一些寄存器来configured/used。这些寄存器可以直接 read/written 因为它是 C 程序可用的内存。
举一个小例子来说明它的样子:
/* Control the PIN10 (input/output) */
/* The CONTROLLER of PIN10 is mapped at the address 0x00400000 */
static volatile uint8_t * const PIN10_CTRL = 0x00400000;
/* PIN10 control the output PIN of the MCU who is connected to a LED */
/* The STATUS of the PIN10 is mapped at the address 0x00400001 */
static volatile uint8_t * const PIN10 = 0x00400001;
*PIN10_CTRL = 0x1; /* Configure the PIN10 as a output PIN */
/* Blink the LED every second */
while (1)
{
*PIN10 = 1;
sleep(1);
*PIN10 = 0;
sleep(1);
}
如果我们现在考虑您的代码:
static volatile ENETPACKET *const _net1 = ((ENETPACKET *)0x00500000);
似乎 你的微控制器的网络接口把 ENETPACKET
的结果放在地址 0x00500000
上。这个地址是固定的,可能可以在你的微控制器的用户手册中找到。
结构是volatile以防止编译器对他将生成的二进制代码做任何假设。如果关键字 volatile 被省略,您可能会对程序应用一些优化,并且数据会过时。
这个地址0x00500000
可能是N x ENETPACKET
个数据包数组的地址。
对于你的第一个问题(有点不清楚),可以考虑如何声明和初始化指向简单对象的指针:
int i; // declares "i" as an "int"
int* p; // declares "p" as a "pointer to an int"
int* pi = &i; // declares "pi" as a pointer-to-int and initializes with address of "i"
同样,去掉各种限定符:
ENETPACKET str; // Declares "str" as an actual ENETPACKET structure
ENETPACKET *pstr = &str; // pstr is a pointer-to-structure set to address of "str"
现在,const
限定符 在 *
之后(以及 在 名称之前)意味着您的代码不能(不得)在其初始化时更改分配给 _net1
变量的值(地址),但指向的实际数据(即结构及其成员的值)可以被改变:指针是const
,不是引用的数据;据推测,这是因为分配的值是硬件中的特定位置。
对于你的第二点,常量前面的(ENETPACKET*)
是一个cast operator;没有它,您的编译器会将 0x00500000
视为 整数 常量并生成如下警告(来自 clang-cl):
warning : incompatible integer to pointer conversion initializing
'volatile ENETPACKET *const' (aka 'volatile struct ENETPACKET_S
*const') with an expression of type 'int' [-Wint-conversion]
添加 explicit cast 告诉编译器:“是的,我知道类型不一样,但我知道我在做什么,希望你将它们视为兼容”谨慎使用强制转换!
第二个(外部)括号实际上不是必需的,但作者为了清楚起见添加了(这是一件好事);它们 可能 如果使用的值从 constant/literal (目前)更改为涉及指针算术的更复杂的表达式,或者在(可能更有可能)使用宏代替固定文字的情况。
我在 C 中有一个结构如下:
typedef struct ENETPACKET_S {
unsigned n_rxcmd, n_txcmd;
uint64_t n_mac; // 8 bytes unsigned or 64 bit
unsigned n_rxmiss, n_rxerr, n_rxcrc, n_txcol;
} ENETPACKET;
正在从下面这个结构的变量定义一个指针:
static volatile ENETPACKET *const _net1 = ((ENETPACKET *)0x00500000);
我有两个问题:
我理解指向结构的指针,但在
_net1
的声明中,定义了来自结构 variable/object 的指针。我不明白。我对
const
指针的((ENETPACKET *)0x00500000)
初始化感到困惑,我不明白这里初始化的是什么以及括号和*
运算符。
看来您正在使用可能带有微控制器的嵌入式设备。在这样的系统中,一些外设可以通过设置一些寄存器来configured/used。这些寄存器可以直接 read/written 因为它是 C 程序可用的内存。
举一个小例子来说明它的样子:
/* Control the PIN10 (input/output) */
/* The CONTROLLER of PIN10 is mapped at the address 0x00400000 */
static volatile uint8_t * const PIN10_CTRL = 0x00400000;
/* PIN10 control the output PIN of the MCU who is connected to a LED */
/* The STATUS of the PIN10 is mapped at the address 0x00400001 */
static volatile uint8_t * const PIN10 = 0x00400001;
*PIN10_CTRL = 0x1; /* Configure the PIN10 as a output PIN */
/* Blink the LED every second */
while (1)
{
*PIN10 = 1;
sleep(1);
*PIN10 = 0;
sleep(1);
}
如果我们现在考虑您的代码:
static volatile ENETPACKET *const _net1 = ((ENETPACKET *)0x00500000);
似乎 你的微控制器的网络接口把 ENETPACKET
的结果放在地址 0x00500000
上。这个地址是固定的,可能可以在你的微控制器的用户手册中找到。
结构是volatile以防止编译器对他将生成的二进制代码做任何假设。如果关键字 volatile 被省略,您可能会对程序应用一些优化,并且数据会过时。
这个地址0x00500000
可能是N x ENETPACKET
个数据包数组的地址。
对于你的第一个问题(有点不清楚),可以考虑如何声明和初始化指向简单对象的指针:
int i; // declares "i" as an "int"
int* p; // declares "p" as a "pointer to an int"
int* pi = &i; // declares "pi" as a pointer-to-int and initializes with address of "i"
同样,去掉各种限定符:
ENETPACKET str; // Declares "str" as an actual ENETPACKET structure
ENETPACKET *pstr = &str; // pstr is a pointer-to-structure set to address of "str"
现在,const
限定符 在 *
之后(以及 在 名称之前)意味着您的代码不能(不得)在其初始化时更改分配给 _net1
变量的值(地址),但指向的实际数据(即结构及其成员的值)可以被改变:指针是const
,不是引用的数据;据推测,这是因为分配的值是硬件中的特定位置。
对于你的第二点,常量前面的(ENETPACKET*)
是一个cast operator;没有它,您的编译器会将 0x00500000
视为 整数 常量并生成如下警告(来自 clang-cl):
warning : incompatible integer to pointer conversion initializing 'volatile ENETPACKET *const' (aka 'volatile struct ENETPACKET_S *const') with an expression of type 'int' [-Wint-conversion]
添加 explicit cast 告诉编译器:“是的,我知道类型不一样,但我知道我在做什么,希望你将它们视为兼容”谨慎使用强制转换!
第二个(外部)括号实际上不是必需的,但作者为了清楚起见添加了(这是一件好事);它们 可能 如果使用的值从 constant/literal (目前)更改为涉及指针算术的更复杂的表达式,或者在(可能更有可能)使用宏代替固定文字的情况。