我遇到了FAT file system的图书馆。它是嵌入式系统的库。在示例代码中,我发现了一些我不理解的有趣行。
以下是有问题的一行::
sd_protocol.spiHwInit=(void *)atmega_spi_init;
其中sd_protocol
是结构SdSpiProtocol sd_protocol;
以下是类型定义:
struct _SdSpiProtocol
{
void *spiHwInterface;
euint8 (*spiHwInit)(void* spiHwInterface);
euint8 (*spiSendByte)(void* spiHwInterface,euint8 data);
};
typedef struct _SdSpiProtocol SdSpiProtocol;
和atmega_spi_init
是以下功能:
euint8 atmega_spi_init(atmegaSpiInterface *iface)
{
euint8 i;
/* Unselect card */
PORTB |= iface->pinSelect;
/* Set as master, clock and chip select output */
DDR_SPI = (1<<DD_MOSI) | (1<<DD_SCK) | 1;
/* Enable SPI, master, set clock rate to fck/2 */
SPCR = (1<<SPE) | (1<<MSTR); /* fsck / 4 */
SPSR = 1; /* fsck / 2 */
/* Send 10 spi commands with card not selected */
for(i=0;i<10;i++)
atmega_spi_send(iface,0xff);
/* Select card */
PORTB &= ~(iface->pinSelect);
return(0);
}
sd_protocol.spiHwInit=(void *)atmega_spi_init;
这不是函数调用,那是什么?
我不明白这行应该做什么,在类型定义中:
euint8 (*spiHwInit)(void* spiHwInterface);
提前致谢!
答案 0 :(得分:3)
答案 1 :(得分:2)
struct _SdSpiProtocol
{
void *spiHwInterface;
euint8 (*spiHwInit)(void* spiHwInterface);
euint8 (*spiSendByte)(void* spiHwInterface,euint8 data);
};
typedef struct _SdSpiProtocol SdSpiProtocol;
spiHwInit
成员是指向void *
参数并返回euint8
的函数的指针。
euint8 atmega_spi_init(atmegaSpiInterface *iface);
sd_protocol.spiHwInit=(void *)atmega_spi_init;
此行是作业。它会将atmega_spi_init
(这是一个函数)转换为(void *)
并将其分配给.spiHwInit
。
然而,由于多个原因,这是错误的。首先,任何C标准都不能将函数指针转换为具有任何明确定义结果的void *
。 对象指针可以转换为void *
并返回到具有明确定义结果的相同类型,但不能转换为函数指针。
其次,(假设atmegaSpiInterface
是结构而不是void *
),代码将一种类型的函数指针转换为void *
,然后转换为不同函数指针的类型。如果通过错误类型的函数指针调用该函数,则行为未定义。
执行此操作的正确方法是将函数atmega_spi_init()
定义为与.spiHwInterface
成员具有相同类型,即使用void *
参数。然后可以在没有强制转换的情况下进行赋值,并且通过.spiHwInterface
的函数调用是完全明确定义的。您只需将iface
参数转换为正确的类型,然后再在函数内使用它。
当然,可能还有其他标准(例如POSIX)或编译器扩展,允许所有这些转换具有明确定义的结果。
答案 2 :(得分:1)
这一行euint8 (*spiHwInit)(void* spiHwInterface);
将spiHwInit
声明为函数的指针。 “有问题”行将指针指向具体函数sd_protocol.spiHwInit
。