【问题标题】:Functions in structure结构中的功能
【发布时间】:2010-11-19 06:32:12
【问题描述】:

结构可以包含函数吗?

【问题讨论】:

  • 他们可以,但是在通常的 C 编程中没有固有的优势。在 C 中,无论如何,所有函数都在全局空间中,因此通过将它们塞入函数中不会隐藏任何信息。 paxdiablo 的示例是将函数组织到结构中的一种方法,但是您必须看到无论如何必须取消引用每个函数才能使用它。 C 语言的标准组织结构是文件,接口在头文件中,实现在源文件中。这就是 libc 的完成方式,也是几乎所有 C 库的完成方式。

标签: c function struct


【解决方案1】:

不,但它们可以包含函数指针。

如果您的意图是在 C 中做某种形式的多态性,那么是的,它可以做到:

typedef struct {
    int (*open)(void *self, char *fspec);
    int (*close)(void *self);
    int (*read)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
    int (*write)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
    // And data goes here.
} tCommClass;

上面的typedef 是我为通用通信库创建的结构。为了初始化变量,您将:

tCommClass *makeCommTcp (void) {
    tCommClass *comm = malloc (sizeof (tCommClass));
    if (comm != NULL) {
        comm->open  = &tcpOpen;
        comm->close = &tcpOpen;
        comm->read  = &tcpOpen;
        comm->write = &tcpWrite;
    }
    return comm;
}

tCommClass *makeCommSna (void) {
    tCommClass *comm = malloc (sizeof (tCommClass));
    if (comm != NULL) {
        comm->open  = &snaOpen;
        comm->close = &snaOpen;
        comm->read  = &snaOpen;
        comm->write = &snaWrite;
    }
    return comm;
}

tCommClass *commTcp = makeCommTcp();
tCommClass *commSna = makeCommSna();

然后,调用函数,例如:

// Pass commTcp as first params so we have a self/this variable
//   for accessing other functions and data area of object.
int stat = (commTcp->open)(commTcp, "bigiron.box.com:5000");

通过这种方式,单一类型可以用于 TCP、SNA、RS232 甚至航母 pidgeons,具有完全相同的接口。

【讨论】:

  • 这也是黑白结构和类的区别之一吗?因为据我所知,唯一的区别是结构具有默认公共和类是默认私有
  • @Josh,我认为您实际上是正确的,公共/私有是 C++ 中结构/联合之间的唯一区别。这个问题是关于 C 的。我怀疑函数 are 在 C++ 中是允许的,因为 struct xyz { int fn(void); } a; 在 g++ 中工作得很好。
  • commTcp.open 周围的括号是不必要的。
  • 您实际上可以在 Linux 内核代码的结构中看到函数的示例。查看 linux 内核:Documentation/vfs.txt
【解决方案2】:

edit 使用“数据类型”消除歧义

不在 C 中。struct 类型只能包含数据。

来自 ISO C99 标准的第 6.7.2.1 节。

结构或联合不得包含不完整或函数类型的成员(因此, 结构不应包含自身的实例,但可以包含指向实例的指针 本身),除了具有多个命名成员的结构的最后一个成员 可能有不完整的数组类型;这样的结构(以及任何包含,可能 递归地,作为这种结构的成员)不应是结构的成员或 数组的元素。

【讨论】:

  • “包含数据类型”是一个危险的模棱两可(至少对于 C++ 用户来说,他们可以在其中声明类型)——“包含数据”似乎更准确。不过,标准中都清楚地表明了... :-)。
【解决方案3】:

不,你不能。结构不能包含函数的声明,但可以包含函数的定义。一个结构只能包含数据类型、指针、指向不同函数的指针。您可以创建一个指向函数的指针,然后从结构中访问。

#include<iostream>
#include<cstring>
using namespace std;

struct full_name
{
  char *fname;
  char *lname;
  void (*show)(char *,char*);
};

void show(char *a1,char * a2)
{
  cout<<a1<<"-"<<a2<<endl;
}

int main()
{  
  struct full_name loki;
  loki.fname="Mohit";
  loki.lname="Dabas";
  loki.show=show;
  loki.show(loki.fname,loki.lname);

  return 0;     
}

【讨论】:

    【解决方案4】:

    在 C 中,允许结构包含数据值而不是函数指针。在 C 中不允许。但在使用 gcc 检查时,以下内容确实可以正常工作。

    enter code here
    
    #include <stdio.h>
    
    struct st_func_ptr{
            int data;
            int (*callback) ();
    };
    
    int cb(){
            printf(" Inside the call back \n");
            return 0;
    }
    
    int main() {
            struct st_func_ptr sfp = {10, cb};
    
            printf("return value = %d \n",sfp.callback());
    
            printf(" Inside main\n");
            return 0;
    }
    

    所以,我很困惑......

    【讨论】:

    • 谁说C的结构中不能有函数指针?
    • 是的,看来你把事情搞混了。允许使用函数指针,但不允许使用函数本身。
    • 回调是一个指向函数的指针,0 个参数返回 int。 C 将允许您通过引用与该函数签名匹配的任何函数来分配回调。初始化列表的使用在这里是新的和特别的。 printf 语句是有效的 C,但不是很好的风格。它的意图令人困惑,如果你看到它远离结构定义,你可能会对它是什么感到困惑,不得不去寻找。
    【解决方案5】:

    没关系。 在linux内核代码中,你会发现很多结构都包含函数。 如:

    /*
    
    
    * The type of device, "struct device" is embedded in. A class
     * or bus can contain devices of different types
     * like "partitions" and "disks", "mouse" and "event".
     * This identifies the device type and carries type-specific
     * information, equivalent to the kobj_type of a kobject.
     * If "name" is specified, the uevent will contain it in
     * the DEVTYPE variable.
     */
    struct device_type {
            const char *name;
            struct attribute_group **groups;
            int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
            void (*release)(struct device *dev);
            int (*suspend)(struct device * dev, pm_message_t state);
            int (*resume)(struct device * dev);
    };
    

    【讨论】:

    • 嗯,它们是指向函数的指针 - 大致相同,只是需要一些努力来初始化它们,当它们为 NULL 或其他无效时尝试使用它们存在风险,并且它们可以在运行时更改....
    【解决方案6】:

    是的,它可以声明一个函数,并且函数定义是不允许的,应该是函数指针。

    它基于 C99 标记结构。

    Lokesh V

    【讨论】:

      【解决方案7】:

      他们可以,但在通常的 C 编程中没有固有的优势。

      在 C 中,无论如何,所有函数都在全局空间中,因此通过将它们塞入函数中不会隐藏任何信息。 paxdiablo 的示例是一种将函数组织到结构中的方法,但您必须看到必须取消对每个函数的引用才能使用它。

      C 的标准组织结构是文件,其中 标头中的接口和源中的实现。

      libc 就是这样完成的,几乎所有的 C 库都是这样完成的。

      现代 C 编译器允许您在同一个源文件中定义和实现函数,甚至在头文件中实现静态函数。不幸的是,这导致了一些关于去哪里的混乱,并且您可以获得不寻常的解决方案,例如将函数塞进结构中,没有标头的纯源程序等。 你失去了以这种方式将接口与实现分离的优势。

      【讨论】: