难以理解函数指针
trouble understanding function pointers
我很难理解函数指针在我正在使用的代码中的工作方式。
该代码描述了 NXP LPC1768 微控制器上闪存的 IAP(应用程序内编程)。
unsigned int flashParamTab[5];
unsigned int flashResultTab[5];
// IAP entry function
#define IAP_LOCATION 0x1FFF1FF1
// In Application Programming function entry
typedef void (*IAP)(unsigned int[], unsigned int[]);
IAP flashIapEntry = (IAP)IAP_LOCATION;
此代码用于各种函数,例如这两个:
// Prepare a sector for write operation.
void flashPrepareSectors(unsigned int startSec, unsigned int endSec){
flashParamTab[0] = IAP_PREPARE_WRITE;
flashParamTab[1] = startSec;
flashParamTab[2] = endSec;
flashIapEntry(flashParamTab, flashResultTab);
}
// Erase a sector.
void flashEraseSectors(unsigned int startSec, unsigned int endSec) {
flashParamTab[0] = IAP_ERASE_SECTORS;
flashParamTab[1] = startSec;
flashParamTab[2] = endSec;
flashIapEntry(flashParamTab, flashResultTab);
}
据我了解:
typedef void (*IAP)(unsigned int[], unsigned int[]);
定义了一个 IAP 数据类型,其中 IAP 是一个指向函数的指针,该函数将两个整数数组作为参数,而不是return 随便什么。
下一步
IAP flashIapEntry = (IAP)IAP_LOCATION;
声明了一个类型为 IAP 的变量 flashIapEntry,它是一个指向内存中特定位置的指针,其中包含一个函数的代码,该函数采用两个整数数组。
我真的搞不懂调用这个函数时会发生什么。
在我看来,在这两种情况下(准备和擦除扇区时)都调用了相同的函数(位于 0x1fff1ff1 的函数),唯一的区别是数组的第一个字段,flashParamTab[0],它定义了这个函数的行为。
我的理解正确吗?
正确。正如 this NXP 应用说明中所述,在您的示例中,flashIapEntry
成为指向函数的指针,该函数将两个整数数组作为参数,并且 returns 无效。这意味着您可以像调用 C 中的任何其他函数一样调用该函数,如下所示:
flashIapEntry(flashParamTab, flashResultTab);
“我真的搞不懂调用这个函数时会发生什么。”
将参数入栈,即当前程序执行位置,然后将程序执行指针设置为0x1FFF1FF1。 IAP 入口函数(位于 0x1FFF1FF1)要执行的命令由您在 flashParamTab
数组中设置的值定义,并且此函数产生的任何结果都将写入 flashResultTab
内存区域。最后,程序执行位置被设置为保存在堆栈中的值,堆栈指针被重置,程序流在调用 flashIapEntry()
后继续,允许您检查 flashResultTab
数组中的结果。
恩智浦控制器上的 IAP 库是硬编码的,ever-present 交付时 MCU 中已有库的源代码。此库未链接,因此您的编译器和链接器都不知道它。
IAP_LOCATION
内存地址是函数所在的物理地址,NXP保证其具有一定的格式和调用约定。为了调用该函数,我们需要使用函数指针,因为实际函数在我们的源代码中的任何地方都不可用。
你可以这样做更具可读性(来自我曾经写过的 IAP 驱动程序):
typedef uint32_t iap_func_t (const uint32_t*, uint32_t*);
static iap_func_t* const iap_entry = (iap_func_t*) IAP_ADDRESS;
const
关键字确保函数指针存储在闪存中,所以这基本上就像我们正常声明函数一样。
然后根据您的需要使用不同的参数调用该函数。
我很难理解函数指针在我正在使用的代码中的工作方式。
该代码描述了 NXP LPC1768 微控制器上闪存的 IAP(应用程序内编程)。
unsigned int flashParamTab[5];
unsigned int flashResultTab[5];
// IAP entry function
#define IAP_LOCATION 0x1FFF1FF1
// In Application Programming function entry
typedef void (*IAP)(unsigned int[], unsigned int[]);
IAP flashIapEntry = (IAP)IAP_LOCATION;
此代码用于各种函数,例如这两个:
// Prepare a sector for write operation.
void flashPrepareSectors(unsigned int startSec, unsigned int endSec){
flashParamTab[0] = IAP_PREPARE_WRITE;
flashParamTab[1] = startSec;
flashParamTab[2] = endSec;
flashIapEntry(flashParamTab, flashResultTab);
}
// Erase a sector.
void flashEraseSectors(unsigned int startSec, unsigned int endSec) {
flashParamTab[0] = IAP_ERASE_SECTORS;
flashParamTab[1] = startSec;
flashParamTab[2] = endSec;
flashIapEntry(flashParamTab, flashResultTab);
}
据我了解:
typedef void (*IAP)(unsigned int[], unsigned int[]);
定义了一个 IAP 数据类型,其中 IAP 是一个指向函数的指针,该函数将两个整数数组作为参数,而不是return 随便什么。
下一步
IAP flashIapEntry = (IAP)IAP_LOCATION;
声明了一个类型为 IAP 的变量 flashIapEntry,它是一个指向内存中特定位置的指针,其中包含一个函数的代码,该函数采用两个整数数组。
我真的搞不懂调用这个函数时会发生什么。 在我看来,在这两种情况下(准备和擦除扇区时)都调用了相同的函数(位于 0x1fff1ff1 的函数),唯一的区别是数组的第一个字段,flashParamTab[0],它定义了这个函数的行为。
我的理解正确吗?
正确。正如 this NXP 应用说明中所述,在您的示例中,flashIapEntry
成为指向函数的指针,该函数将两个整数数组作为参数,并且 returns 无效。这意味着您可以像调用 C 中的任何其他函数一样调用该函数,如下所示:
flashIapEntry(flashParamTab, flashResultTab);
“我真的搞不懂调用这个函数时会发生什么。”
将参数入栈,即当前程序执行位置,然后将程序执行指针设置为0x1FFF1FF1。 IAP 入口函数(位于 0x1FFF1FF1)要执行的命令由您在 flashParamTab
数组中设置的值定义,并且此函数产生的任何结果都将写入 flashResultTab
内存区域。最后,程序执行位置被设置为保存在堆栈中的值,堆栈指针被重置,程序流在调用 flashIapEntry()
后继续,允许您检查 flashResultTab
数组中的结果。
恩智浦控制器上的 IAP 库是硬编码的,ever-present 交付时 MCU 中已有库的源代码。此库未链接,因此您的编译器和链接器都不知道它。
IAP_LOCATION
内存地址是函数所在的物理地址,NXP保证其具有一定的格式和调用约定。为了调用该函数,我们需要使用函数指针,因为实际函数在我们的源代码中的任何地方都不可用。
你可以这样做更具可读性(来自我曾经写过的 IAP 驱动程序):
typedef uint32_t iap_func_t (const uint32_t*, uint32_t*);
static iap_func_t* const iap_entry = (iap_func_t*) IAP_ADDRESS;
const
关键字确保函数指针存储在闪存中,所以这基本上就像我们正常声明函数一样。
然后根据您的需要使用不同的参数调用该函数。