Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
“替代方案”;“子类化”;C中的结构_C_Sockets_Struct - Fatal编程技术网

“替代方案”;“子类化”;C中的结构

“替代方案”;“子类化”;C中的结构,c,sockets,struct,C,Sockets,Struct,我听说在设计BSD套接字库时,C编程缺少某种模式或特性,导致了我们今天的设计 例如,中的struct-socketaddr\u在传递到系统调用(如bind)时被强制转换为struct-socketaddr 从GNU libc头文件: /* POSIX.1g specifies this type name for the `sa_family' member. */ typedef unsigned short int sa_family_t; /* This macro is us

我听说在设计BSD套接字库时,C编程缺少某种模式或特性,导致了我们今天的设计

例如,中的
struct-socketaddr\u在传递到系统调用(如
bind
)时被强制转换为
struct-socketaddr

从GNU libc头文件:

/* POSIX.1g specifies this type name for the `sa_family' member.  */
    typedef unsigned short int sa_family_t;

/* This macro is used to declare the initial common members
   of the data types used for socket addresses, `struct sockaddr',
   `struct sockaddr_in', `struct sockaddr_un', etc.  */

#define __SOCKADDR_COMMON(sa_prefix) \
  sa_family_t sa_prefix##family

#define __SOCKADDR_COMMON_SIZE  (sizeof (unsigned short int))

/* Structure describing a generic socket address.  */
struct sockaddr
  {
    __SOCKADDR_COMMON (sa_);    /* Common data: address family and length.  */
    char sa_data[14];       /* Address data.  */
  };

/* Structure describing an Internet socket address.  */
struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;         /* Port number.  */
    struct in_addr sin_addr;        /* Internet address.  */

    /* Pad to size of `struct sockaddr'.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
               __SOCKADDR_COMMON_SIZE -
               sizeof (in_port_t) -
               sizeof (struct in_addr)];
  };

/* Internet address.  */
typedef uint32_t in_addr_t;
struct in_addr
  {
    in_addr_t s_addr;
  };
示例程序:

int main(int argc, char *argv[]) {
    ...

    // Initialize the server address
    struct sockaddr_in serv_addr;
    bzero((char *)&serv_addr, sizeof(serv_addr));

    serv_addr = (struct sockaddr_in) {
        .sin_port = htons(port),
        .sin_family = AF_INET ,
        .sin_addr.s_addr = INADDR_ANY
    };

    // Bind the server address to the TCP/IP socket
    int status = bind(server_socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

    ...
}

我想不出还有什么其他方法可以实现这个通用接口。有什么想法吗?

在设计BSD套接字库时,我不会说C缺少子类化模式。相反,BSD套接字API设计人员专门利用了这种模式。将结构转换为基本结构(具有较少字段的更通用的结构)并返回到专用结构是非常常见且完全受支持的。C甚至有一些保证来确保它的可移植性:如果结构定义的第一个元素是另一个结构,C保证封闭结构的第一个成员的类型、内存地址和布局与类型相同,封闭结构的内存地址和布局转换为其第一个成员的类型。

在设计BSD套接字库时,我不会说C缺少子类化模式。相反,BSD套接字API设计人员专门利用了这种模式。将结构转换为基本结构(具有较少字段的更通用的结构)并返回到专用结构是非常常见且完全受支持的。C甚至有一些保证来确保它的可移植性:如果结构定义的第一个元素是另一个结构,C保证封闭结构的第一个成员的类型、内存地址和布局与类型相同,封闭结构的内存地址和布局强制转换为其第一个成员的类型。

您可以使用委托模式来支持C中的一种继承形式。它看起来很漂亮,很通用,但重量很重:有很多潜在的失败点,需要一些堆分配,等等,我猜他们不想让操作系统API有这样的分量

这里有一个例子

struct ShapeDelegate {
  double (*getSurfaceArea)(void* data);
  int (*isInside)(void* data, double x, double y);
  void (*destroy)(void* data);
}

struct Shape {
  void* data;
  struct ShapeDelegate delegate;
}

double Shape_getSurfaceArea(Shape* self) {
  return self->delegate.getSurfaceArea(self->data);
}

int Shape_isInside(Shape* self, double x, double y) {
  return self->delegate.isInside(self->data, x, y);
}

void Shape_destroy(Shape* self) {
  if (self->delegate.destroy != NULL)
    self->delegate.destroy(self->data);
}
现在,比方说,你想要一个圆作为形状的实现

struct CircleData {
  double x, y, r;
}

double Circle_getSurfaceArea(void* data) {
  CircleData* self = (CircleData*)data;
  return 2 * M_PI * self->r * self->r;
}

int Circle_isInside(void* data, double x, double y) {
  double dist;
  CircleData* self = (CircleData*)data;
  dist = sqrt(sqr(x - self->x) + sqr(y - self->y)); 
  return dist < self->r;
}

void Circle_destroy(void* data) {
  free(data);
}

struct ShapeDelegate Circle_ShapeDelegate {
   Circle_getSurfaceArea,
   Circle_isInside,
   Circle_destroy
};

您可以使用委托模式来支持C中的某种形式的继承。它看起来很漂亮,是通用的,但重量相当大:有很多潜在的故障点,需要一些堆分配,等等。我想他们不希望OS API有这种重量

这里有一个例子

struct ShapeDelegate {
  double (*getSurfaceArea)(void* data);
  int (*isInside)(void* data, double x, double y);
  void (*destroy)(void* data);
}

struct Shape {
  void* data;
  struct ShapeDelegate delegate;
}

double Shape_getSurfaceArea(Shape* self) {
  return self->delegate.getSurfaceArea(self->data);
}

int Shape_isInside(Shape* self, double x, double y) {
  return self->delegate.isInside(self->data, x, y);
}

void Shape_destroy(Shape* self) {
  if (self->delegate.destroy != NULL)
    self->delegate.destroy(self->data);
}
现在,比方说,你想要一个圆作为形状的实现

struct CircleData {
  double x, y, r;
}

double Circle_getSurfaceArea(void* data) {
  CircleData* self = (CircleData*)data;
  return 2 * M_PI * self->r * self->r;
}

int Circle_isInside(void* data, double x, double y) {
  double dist;
  CircleData* self = (CircleData*)data;
  dist = sqrt(sqr(x - self->x) + sqr(y - self->y)); 
  return dist < self->r;
}

void Circle_destroy(void* data) {
  free(data);
}

struct ShapeDelegate Circle_ShapeDelegate {
   Circle_getSurfaceArea,
   Circle_isInside,
   Circle_destroy
};

你最后一句话是什么意思?它如何/为什么工作?他们为什么要这么做?关于如何实现类似的子类化方案的基本细节?我的意思是,这看起来是最优雅的实现方式(参见我的“示例程序”)。我记得几年前我的一位教授指出,有另一种方法可以做到这一点。你最后一句话是什么意思?它如何/为什么工作?他们为什么要这么做?关于如何实现类似的子类化方案的基本细节?我的意思是,这看起来是最优雅的实现方式(参见我的“示例程序”)。我记得几年前我的一位教授提到有另一种方法可以实现这一点。Monkey答案中的委托模式很有趣,我一直想知道它是否出现在生产代码中。但是,我同意您的观点,即强制转换结构的概念是合法的,因为它是由C标准的结构对齐规则强制执行的。@OregonTrail是的,它绝对是合法的!这种模式的典型代表是几乎每个操作系统内核中的VFS开关(它接受诸如“打开”和“删除”之类的通用文件操作,并将它们委托给实际的文件系统实现)。以下是Linux版本的部分定义:Monkey答案中的委托模式很有趣,我一直想知道它是否出现在生产代码中。但是,我同意您的观点,即强制转换结构的概念是合法的,因为它是由C标准的结构对齐规则强制执行的。@OregonTrail是的,它绝对是合法的!这种模式的典型代表是几乎每个操作系统内核中的VFS开关(它接受诸如“打开”和“删除”之类的通用文件操作,并将它们委托给实际的文件系统实现)。以下是Linux版本的部分定义: