0

I came across with a library for FAT file system. It is a library for embedded systems. In the example code I found some interesting lines which I do not understand.

Here is the problematic line::

sd_protocol.spiHwInit=(void *)atmega_spi_init;

where sd_protocol is a struct SdSpiProtocol sd_protocol;

Here is the type definition:

struct _SdSpiProtocol
{
    void *spiHwInterface;
    euint8 (*spiHwInit)(void* spiHwInterface);
    euint8 (*spiSendByte)(void* spiHwInterface,euint8 data);
};
typedef struct _SdSpiProtocol SdSpiProtocol;

and atmega_spi_init is the following function:

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; this is not a function call, then what it is?

and I do not understand what this line supposed to do either, in the type definition:

euint8 (*spiHwInit)(void* spiHwInterface);

Thanks in advance!

Bence Kaulics
  • 7,066
  • 7
  • 33
  • 63

3 Answers3

3

It is not a function call but a function pointer:

How do function pointers in C work?

And your line is cast from a specific function pointer to a void pointer.

Community
  • 1
  • 1
2
struct _SdSpiProtocol
{
  void *spiHwInterface;
  euint8 (*spiHwInit)(void* spiHwInterface);
  euint8 (*spiSendByte)(void* spiHwInterface,euint8 data);
};
typedef struct _SdSpiProtocol SdSpiProtocol;

The spiHwInit member is a pointer to function taking a void * parameter and returning euint8.

euint8 atmega_spi_init(atmegaSpiInterface *iface);

sd_protocol.spiHwInit=(void *)atmega_spi_init;

This line is an assignment. It converts atmega_spi_init (which is a function) to a (void *) and assigns it to .spiHwInit.

However, this is wrong for more than one reason. Firstly, a function pointer can not, by any C standard, be converted to a void * with any well-defined result. An object pointer can be converted to void * and back to the same type with well-defined results, but not a function pointer.

Secondly, (assuming that atmegaSpiInterface is a structure and not a void *), the code converts one type of function pointer to void * and then to a different type of function pointer. If the function is called through a function pointer of the wrong type, the behaviour is undefined.

The correct way to do this is to define the function atmega_spi_init() to have the same type as the .spiHwInterface member, i.e. with a void * parameter. The assignment can then be made without a cast, and the function call through the .spiHwInterface is perfectly well-defined. You just have convert the iface parameter to the correct type before using it inside the function.

Of course, there may other standards (such as POSIX) or compiler extension that allow all of these conversions with well-defined results.

Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
  • As a matter of fact it is not my code, but thanks for this additional information. – Bence Kaulics Nov 30 '14 at 18:03
  • 1
    As a note, POSIX defines those conversions. – mafso Nov 30 '14 at 22:44
  • @mafso: Good to know! Do you have a reference for that? – Nisse Engström Nov 30 '14 at 23:26
  • Not a normative one unfortunately, @NisseEngström, but [here](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html) is an example (under "Application Usage") stating explicitly that `void *`-to`function pointer conversion are well-defined. – mafso Dec 01 '14 at 01:52
1

This line euint8 (*spiHwInit)(void* spiHwInterface); declares spiHwInit as a pointer to function. The "problematic" line sets that pointer to a concrete function sd_protocol.spiHwInit.

Nick
  • 3,205
  • 9
  • 57
  • 108