结构体的定义位置不正确导致的错误

时间:2022-09-21 16:46:24
今天遇到一个结构体数组的定义错误,MDK编译器报错为:
error: expression must be a pointer to a complete object type
本以为是函数形参为指针,调的是结构体变量名而出错,以前遇到过这种调用错误。但是检查后发现并没有调用问题。结构体数组定义如下:

"func.c"中:
struct msg_param{
uint16_t number;
uint16_t data;
};
const struct msg_param msg_group[]{
{1,0x0001},
{2,0x00F1},
{3,0x00FF},
};

"message.c"中:
extern const struct msg_param msg_group[];/*结构体数组声名*/
void msg_write(uint16_t nbr, uint16_t data); /*函数声名*/

msg_write(msg_group[1].number, msg_group[1].data); /*按该结构体写数据*/

然后编译就出现了:
error: expression must be a pointer to a complete object type
结过反复检查,认为问题出在结构体数组声名上。在message.c中声名了在其他文件中定义的结构体数组,而没有放在.h文件中,这样是不是有问题?仔细想想,没问题呀,在.h中包含进来以后,跟直接在.c中声名应该是一样的。
再仔细检查,发现是不是因为struct msg_param没有被声名呢?于是在message.c中增加声名结构体语句,成为下面这样:
extern const struct msg_param;/*声名结构体*/
extern const struct msg_param msg_group[];/*结构体数组声名*/
void msg_write(uint16_t nbr, uint16_t data); /*函数声名*/
msg_write(msg_group[1].number, msg_group[1].data); /*按该结构体写数据*/

结果还是报错。然后忽然想起来,结构体定义的是一种类型,怎么可以被“声名”呢!
只有变量和函数才能被“声名”呀!
于是把message.c的结构体声名变成结构体定义,成为这样:
struct msg_param{
uint16_t number;
uint16_t data;
};   /*将func.c中的结构体定义复制到这里*/
extern const struct msg_param msg_group[];/*结构体数组声名*/
void msg_write(uint16_t nbr, uint16_t data); /*函数声名*/
msg_write(msg_group[1].number, msg_group[1].data); /*按该结构体写数据*/

编译通过!
至此又对结构体定义有了进一步的理解,结构体定义的一种类型!
typedef struct xx{;}XXX;之类的,又是把结构体类型定义成一个更省事的结构体类型!
虽然之前在教材和文献上屡次看到这句话,但过久了,还是没有实际的理解。
因为通常写程序都是按“规矩”把结构体定义在.h文件中的,这样肯定就被多个.c包含了,不会出现找不到结构体类型的情况。
这次定义在.c中,结果就出了问题。看来前人在C语言编程中创造了.h文件,并且一再强调结构体定义要放在.h中,还是很有他们的道理的,玄机颇深啊。