1

BSD ソケット ライブラリが設計されていたとき、C プログラミングには、現在の設計につながった特定のパターンまたは機能が欠けていたと聞いています。

たとえば、 aは、などのシステム コールに渡されるときstruct socketaddr_inに a にキャストされます。struct socketaddrbind

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

    ...
}

この汎用インターフェースを他にどのように配置できるかは考えられません。何か案は?

4

2 に答える 2

3

デリゲート パターンを使用して、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);
}

ここで、Shape の実装として Circle が必要だとします。

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

ある種のコンストラクターが必要です

void
Shape_initAsCircle(Shape* self, double x, double y, double r) {
  CircleData* data;

  data = (CircleData*)malloc(sizeof(CircleData));
  data->x = x, data->y = y, data->r = r;

  self->data = data;
  self.delegate = Circle_ShapeDelegate;
}
于 2013-06-01T00:30:51.767 に答える
1

BSD ソケット ライブラリが設計されていたとき、C にサブクラス化パターンがなかったとは言いません。それどころか、BSD ソケット API の設計者は特にこのパターンを利用しました。構造体を基本構造体 (より少ないフィールドを持つより一般的な構造体) にキャストし、特殊な構造体に戻すことは非常に一般的であり、完全にサポートされています。C には、移植可能に動作することを保証するいくつかの保証もあります。構造体定義の最初の要素が別の構造体である場合、C は、それを囲む構造体の最初のメンバーの型、メモリ アドレス、およびレイアウトが型、メモリと同じであることを保証します。最初のメンバーの型にキャストされた外側の構造体のアドレスとレイアウト。

于 2013-06-01T00:28:19.960 に答える