问题:使用函数指针调用函数程序跑飞。
场景描述:
在A文件内正常调用函数指针可以初始化,可以调用。
到main函数内初始化的test无法正常使用函数指针。
/***************************************/
a.h 文件
#ifndef A_H
#define A_H
#include "x.h"
typedef struct
{
bool value;
void (*p)(void);
}struct_a;
void init(struct_a* s);
#endif
/***************************************/
a.c文件
#include "a.h"
void a_func(void)
{
xxxxx;
}
void init(struct_a* s)
{
s->value = 1;
s->p = a_func;
}
/***************************************/
问题就和x.h有关
x.h文件内容
#ifndef x_H
#define x_H
#include "a.h"
#pragma pack(1)
#endif
/***************************************/
main.c文件
#include "x.h"
#include "a.h"
struct_a test;
int main()
{
init(&test);
test.p(); //这边程序跑飞
return 0;
}
问题解决
后查看内存,发现内存中保存数据如下表,函数入口地址是0x080067d0。
仿真函数指针p的内容为8;
0x2000, 0198 | 0x0006,7d00 |
ox2000, 019c | 0x0000, 0008 |
最后发现和地址对齐有关#pragma pack(1) 1
删除#pragma pack(1) 1 程序可以在main.c内正常调用。
问题到这解决了一半,因为只解释了问什么main不能调用。解决方法也只是删除#pragma pack(1)
剩下一个问题是为什么a文件可以正常使用p指针?
返回重新查看头文件发现,a的头文件包含x的头文件,x的头文件也包含了a的头文件。
同时main文件包含了x的头文件。
这里面涉及到预处理的知识,并不是很懂,大胆猜测一下,头文件重复包含的情况下。
(1)处理到main.c的时候,先处理x.h,发现x.h包含了a.h,继续处理a.h,此时发现重复包含x.h,直接跳过了,然后发现了struct_a,此时#pragma pack(1) 并没有生效。处理完a.h以后回到x.h,#pragma pack(1)才生效。所以main文件内的struct_a是没有按照一字节对齐去解析的。
(2)处理到a.c的时候,#pragma pack(1)已经生效了,所以在a.c的作用域范围内struct_a是按照1字节解析了,所以p指针在a.c内能正常使用,而在main.c内无法正常使用。
这地方也不是很懂,大概理解到这把,最后只能说,包含头文件的时候小心点,非必要不包含!!!大部分情况下extern下可以了。还有注意下#pragma pack(1)的使用。