-1

I have built the following C example trying to simulate simplistic generic driver code which can be used in small ARM micro-controllers:

#include <stdio.h>
#include <string.h>

typedef unsigned char uint8_t;
typedef void (*generic_func_t)(uint8_t);

typedef struct {
        generic_func_t init;
        generic_func_t open;
        generic_func_t read;
        generic_func_t write;
        generic_func_t close;
        generic_func_t exit;
} driver_t;

void USB_init(uint8_t x)
{
        /* here body of this f-n */
        printf("USB_open 0x%x\n", x);
}

void USB_open(uint8_t x)
{
        /* here body of this f-n */
        printf("USB_open 0x%x\n", x);
}

void USB_read(uint8_t x)
{
        /* here body of this f-n */
        printf("USB_read 0x%x\n", x);
}

void USB_write(uint8_t x)
{
        /* here body of this f-n */
        printf("USB_write 0x%x\n", x);
}

void USB_close(uint8_t x)
{
        /* here body of this f-n */
        printf("USB_close 0x%x\n", x);
}

void USB_exit(uint8_t x)
{
        /* here body of this f-n */
        printf("USB_close 0x%x\n", x);
}

typedef struct driver_t USB_driver;

#if 1
        USB_driver.init = &USB_init;
        USB_driver.open = &USB_open;
        USB_driver.read  = &USB_read;
        USB_driver.write = &USB_write;
        USB_driver.close = &USB_close;
        USB_driver.exit  = &USB_exit;
#endif

#if 1
void main(void) {}
#endif
#if 0
void main(void) {
        USB_driver.init(0x01);
        USB_driver.open(0x02);
        USB_driver.read(0x03);
        USB_driver.write(0x04);
        USB_driver.close(0x05);
        USB_driver.exit(0x06);
}
#endif

The following error appears:

[user@localhost fn-ptr]$ emacs fn-ptr.c

(emacs:4983): Gtk-WARNING **: Allocating size to Emacs 0xdb4270 without calling gtk_widget_get_preferred_width/height(). How does the code know the size to allocate?
[user@localhost fn-ptr]$ gcc fn-ptr.c
fn-ptr.c:78:11: error: expected identifier or ‘(’ before ‘.’ token
 USB_driver.init = &USB_init;
           ^
fn-ptr.c:79:11: error: expected identifier or ‘(’ before ‘.’ token
 USB_driver.open = &USB_open;
           ^
fn-ptr.c:80:11: error: expected identifier or ‘(’ before ‘.’ token
 USB_driver.read  = &USB_read;
           ^
fn-ptr.c:81:11: error: expected identifier or ‘(’ before ‘.’ token
 USB_driver.write = &USB_write;
           ^
fn-ptr.c:82:11: error: expected identifier or ‘(’ before ‘.’ token
 USB_driver.close = &USB_close;
           ^
fn-ptr.c:83:11: error: expected identifier or ‘(’ before ‘.’ token
 USB_driver.exit  = &USB_exit;
           ^
[user@localhost fn-ptr]$ 

The question here is: what should I do to make this code to work, since the following single function pointer example, upon which this code is built, works perfectly:

typedef unsigned char uint8_t;
typedef void (*generic_func_t)(uint8_t);

generic_func_t init;

void USB_init(uint8_t x)
{
        /* here body of this f-n */
        printf("USB_open 0x%x\n", x);
}

init = &USB_init;
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
nobody
  • 11
  • 5
  • Is the typedef what is confusing here? Are you intending the line `typedef struct driver_t USB_driver;` to declare a USB_driver variable? – Joe Nov 15 '17 at 07:41
  • 1
    `init = &USB_init;` No, this doesn't work in standard C. You can't run code at file scope, you can only declare variables there. – Lundin Nov 15 '17 at 07:49
  • Joe, you are completely right, as alseether! typedef struct driver_t USB_driver; defines USB_driver as type, NOT variable. I predefined it, in correct way, so All Good! Did not do embedded C for 7 years, as we speak, but I am returning quickly to my senses. Now, everything is working! :-) – nobody Nov 15 '17 at 12:05
  • Lundin, this idiotic mistake I did since I tried something else (to predefine structure as .init etc), but situation suddenly went out of my control, and I got lost. :-(( – nobody Nov 15 '17 at 12:06

3 Answers3

1

Make USB_driver a variable by just removing the typedef struct from typedef struct driver_t USB_driver; and use the code in the main to init it.

Like this:

driver_t USB_driver;

int main(void) {
    USB_driver.init = &USB_init;
    USB_driver.open = &USB_open;
    USB_driver.read  = &USB_read;
    USB_driver.write = &USB_write;
    USB_driver.close = &USB_close;
    USB_driver.exit  = &USB_exit;

    USB_driver.init(0x01);
    USB_driver.open(0x02);
    USB_driver.read(0x03);
    USB_driver.write(0x04);
    USB_driver.close(0x05);
    USB_driver.exit(0x06);

    return 0;
}

Or better yet make new create function:

void USB_Driver_create(driver_t *driver)
{
    driver->init = &USB_init;
    driver->open = &USB_open;
    driver->read  = &USB_read;
    driver->write = &USB_write;
    driver->close = &USB_close;
    driver->exit  = &USB_exit;
}
Mihayl
  • 3,821
  • 2
  • 13
  • 32
  • Exactly! An excellent answer... I did achieved this two days ago, but today I did the Politically Correct one with Designated Initializator: https://stackoverflow.com/questions/330793/how-to-initialize-a-struct-in-accordance-with-c-programming-language-standards. This one I wanted to achieve, and I did it, with all your help! Thank You again! – nobody Nov 16 '17 at 09:58
0

First of all, USB_driver is a type, not a variable. You need to have a variable of this type first to access the members (for example, initialize the values of the members).

That said, at a first look, it seems

    USB_driver.init = &USB_init;
    USB_driver.open = &USB_open;
    USB_driver.read  = &USB_read;
    USB_driver.write = &USB_write;
    USB_driver.close = &USB_close;
    USB_driver.exit  = &USB_exit;

these statements, the assignment statements, resides in file scope. That is not allowed. Assignment operation (different than initialization) is allowed only in block scope.

You need them to have them in block scope, inside some function, main(), probably.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • Nope, This does not work. I did what you have suggested. I put the definition inside the main, ONLY USB_driver.init = &USB_init;, and got the same error! – nobody Nov 15 '17 at 07:53
  • @nobody that is previous to my edit or after that? – Sourav Ghosh Nov 15 '17 at 07:54
  • Sourav, I added to the comment. You can copy and paste in you Linux and try it yourself, to see the same I am seeing. Thank you. – nobody Nov 15 '17 at 07:56
  • @nobody please see "You need to have a variable of this type"...part. – Sourav Ghosh Nov 15 '17 at 07:57
  • Sourav, you are correct. I made very stupid overlook, since I tried to experiment out of exe code, rather with structures, and somehow I switched in desperation to exe code outside of the scope! But I needed also to predefine as definition USB_driver variable! Thank you! – nobody Nov 15 '17 at 09:11
-1

You must declare a variable of type USB_driver like

void main(void) {
    USB_driver dr
    dr.init(0x01);
    dr.open(0x02);
    dr.read(0x03);
    dr.write(0x04);
    dr.close(0x05);
    dr.exit(0x06);
}

Try with that

alseether
  • 1,889
  • 2
  • 24
  • 39
  • This will not work. It is obvious. USB_driver is already defined as: typedef struct driver_t USB_driver; and if I replace mine with your definition. there is nowhere USB_init etc. set of function pointers involved. – nobody Nov 15 '17 at 07:59
  • Not so obvious, i think. `typedef struct driver_t USB_driver` defines `USB_driver` **as a type**, not a variable. When you try to call `USB_driver.init()` that's a *static like* call (if this was OOP), but is C and that kind of function call is not supported – alseether Nov 15 '17 at 08:19
  • 1
    I fixed the problem. I finally defined out of exe scope USB_driver variable as variable! Now everuthing does work. :-) – nobody Nov 15 '17 at 09:14