我有一个带有10个功能指针的结构。该结构的全局实例是指向局部功能的初始化机智函数指针。在我的应用程序中,使用任何一个或多个函数引用导致链接器在地图文件中包含所有10个功能。
为了节省内存,我需要链接器来包括应用程序中使用的那些功能。并非结构中引用的所有功能。
struct in File r_adc_api.h (来自制造商)
typedef struct st_adc_api
{
ssp_err_t (* open)(adc_ctrl_t * const p_ctrl, adc_cfg_t const * const p_cfg);
ssp_err_t (* scanCfg)(adc_ctrl_t * const p_ctrl, adc_channel_cfg_t const * const p_channel_cfg);
ssp_err_t (* scanStart)(adc_ctrl_t * const p_ctrl);
ssp_err_t (* scanStop)(adc_ctrl_t * const p_ctrl);
ssp_err_t (* scanStatusGet)(adc_ctrl_t * const p_ctrl);
ssp_err_t (* read)(adc_ctrl_t * const p_ctrl, adc_register_t const reg_id, adc_data_size_t * const p_data);
ssp_err_t (* sampleStateCountSet)(adc_ctrl_t * const p_ctrl, adc_sample_state_t * p_sample);
ssp_err_t (* close)(adc_ctrl_t * const p_ctrl);
ssp_err_t (* infoGet) (adc_ctrl_t * const p_ctrl, adc_info_t * const p_adc_info);
ssp_err_t (* versionGet)(ssp_version_t * const p_version);
} adc_api_t;
**标题r_adc.h **(来自制造商)
extern const adc_api_t g_adc_on_adc;
分配和功能定义在文件r_adc.c (来自制造商)
const adc_api_t g_adc_on_adc =
{
.open = R_ADC_Open,
.scanCfg = R_ADC_ScanConfigure,
.infoGet = R_ADC_InfoGet,
.scanStart = R_ADC_ScanStart,
.scanStop = R_ADC_ScanStop,
.scanStatusGet = R_ADC_CheckScanDone,
.sampleStateCountSet = R_ADC_SetSampleStateCount,
.read = R_ADC_Read,
.close = R_ADC_Close,
.versionGet = R_ADC_VersionGet
};
和##功能定义##
**地图文件**地图文件
在我的应用程序中,如果我使用adc_on_g_adc.open(...);链接器将所有10个符号拉到地图文件,而不仅仅是拉 r_adc_open();
即使调用一个函数,可能会导致.map文件从结构中摘取所有功能?
编辑:将所有这些放在一个文件中,给出了我需要的地图文件。IAR编译器省略了未使用的功能。当我使用多个标头和源时,只是不起作用。
如果用函数指针填充结构,就链接器而言,函数已被"使用"。
用链接器应该用什么替换R_ADC_ScanConfigure
的内容来考虑一下。它不能选择将g_adc_on_adc.scanCfg
设置为null,对吗?它不知道对象代码实际上未调用g_adc_on_adc.scanCfg
。
基本上,这是唯一的选择是在输出中包括R_ADC_ScanConfigure
。
但是,如果不是在结构中分配 R_ADC_ScanConfigure
you> you 将 g_adc_on_adc.scanCfg
设置为null,则链接器将能够从输出中省略 R_ADC_ScanConfigure
。
const adc_api_t g_adc_on_adc =
{
.open = R_ADC_Open,
.scanCfg = NULL,
.infoGet = R_ADC_InfoGet,
.scanStart = R_ADC_ScanStart,
.scanStop = R_ADC_ScanStop,
.scanStatusGet = R_ADC_CheckScanDone,
.sampleStateCountSet = R_ADC_SetSampleStateCount,
.read = R_ADC_Read,
.close = R_ADC_Close,
.versionGet = R_ADC_VersionGet
};
当然,如果您的代码最终确实调用了g_adc_on_adc.scanCfg
,您将尝试在地址0(可能)运行代码,这确实是一件非常糟糕的事情。您可以将.scanCfg
指向一个函数,该功能只需在控制台上/串行端口/down上打印出一个讨厌的错误消息/否则,至少您知道某事已出现。
您要寻找的功能称为虚拟函数消除,并且只能执行您想要的功能,但仅适用于C 中的虚拟函数。
在您的代码中,所有编译器所看到的都是用一些指针的函数的指针初始化的结构。如果此结构是全局的或以某种方式从该模块导出的编译器必须假定使用结构的所有初始化部分。
当链接器掌握所有这些时,就会看到对结构的引用,仅此而已。那里没有信息告诉链接器使用了结构的哪一部分。
将所有内容都放在同一模块中时,编译器可以找出您实际引用的功能并直接去那里,这将使结构无参考,这意味着它可以被扔掉,并在其上所有引用对其他功能。