【问题标题】:Array of function pointers as a member of a C struct [duplicate]作为C结构成员的函数指针数组[重复]
【发布时间】:2017-11-15 07:36:42
【问题描述】:

我构建了以下 C 示例,试图模拟可用于小型 ARM 微控制器的简单通用驱动程序代码:

#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

出现如下错误:

[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]$ 

这里的问题是:我应该怎么做才能使这段代码工作,因为下面这个代码构建的单函数指针示例可以完美地工作:

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;

【问题讨论】:

  • typedef 是这里令人困惑的地方吗?您是否打算在 typedef struct driver_t USB_driver; 行声明一个 USB_driver 变量?
  • init = &amp;USB_init; 不,这在标准 C 中不起作用。你不能在文件范围内运行代码,你只能在那里声明变量。
  • 乔,你是完全正确的,同样! typedef struct driver_t USB_driver;将 USB_driver 定义为类型,而非变量。我以正确的方式预定义了它,所以一切都好!正如我们所说,已经有 7 年没有做嵌入式 C 了,但我很快就恢复了理智。现在,一切正常! :-)
  • Lundin,我犯了这个愚蠢的错误,因为我尝试了其他方法(将结构预定义为 .init 等),但情况突然失控了,我迷路了。 :-((

标签: c function-pointers


【解决方案1】:

只需从typedef struct driver_t USB_driver; 中删除typedef struct 即可将USB_driver 设为变量,然后使用main 中的代码对其进行初始化。

像这样:

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;
}

或者更好的是创建新的创建函数:

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;
}

【讨论】:

  • 没错!一个很好的答案......我在两天前确实做到了这一点,但今天我用指定的初始化器做了政治正确的一个:stackoverflow.com/questions/330793/…。这是我想要实现的,我做到了,在你们的帮助下!再次感谢您!
【解决方案2】:

首先,USB_driver 是一个类型,而不是一个变量。您需要先拥有该类型的变量才能访问成员(例如,初始化成员的值)。

也就是说,乍一看,似乎

    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;

这些语句,即赋值语句,位于文件范围内。这是不允许的。赋值操作(不同于初始化)只允许在块范围内。

您可能需要将它们放在块范围内,在某个函数内,main(),可能。

【讨论】:

  • 不,这不起作用。我按照你的建议做了。我把定义放在main里面,ONLY USB_driver.init = &USB_init;,得到了同样的错误!
  • @nobody 在我的编辑之前或之后?
  • Sourav,我添加到评论中。您可以复制并粘贴到您的 Linux 中并自己尝试,以查看与我所看到的相同。谢谢。
  • @nobody 请参阅“您需要有这种类型的变量”...部分。
  • 苏拉夫,你是对的。我做了一个非常愚蠢的忽略,因为我试图用 exe 代码而不是结构进行试验,不知何故我绝望地切换到了范围之外的 exe 代码!但我还需要预定义为定义 USB_driver 变量!谢谢!
【解决方案3】:

您必须声明一个USB_driver 类型的变量,例如

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

试试看

【讨论】:

  • 这行不通。这很明显。 USB_driver 已经定义为: typedef struct driver_t USB_driver;如果我用你的定义代替我的。没有任何地方涉及 USB_init 等函数指针集。
  • 我认为不是很明显。 typedef struct driver_t USB_driverUSB_driver 定义为类型,而不是变量。当您尝试调用 USB_driver.init() 时,这是一个 static like 调用(如果这是 OOP),但它是 C 并且不支持这种函数调用
  • 我解决了这个问题。我终于将 exe 范围外的 USB_driver 变量定义为变量!现在一切都起作用了。 :-)
猜你喜欢
  • 2010-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多