我现在有一个需要使用8个成员的结构。

typedef struct Foo_s
{
    uint8_t a;
    uint8_t b;
    uint8_t c;
    uint16_t d;
    uint8_t e;
    uint16_t f;
    uint32_t g;
    uint32_t h;
} Foo_s;

这个结构有两个用例,read和write,read使用所有8个成员,write只使用前5个(a-e)。
目前,我已经将其分为两个单独的结构,一个用于读取(有8个成员)和一个用于写入(有5个成员),但是有人建议我可以同时使用一个结构,并且在传递“写入”功能所需的成员时,只访问前5个成员。
if(x == y){
    BarRead(&readStruct);
} else {
    BarWrite(&writeStruct);
}

与其传递readStructwriteStruct,不如只使用一个结构genericStruct。对于if条件,我可以通过&genericStruct,这将很好,但是,我不知道在else条件下通过什么。
我只想在else条件下传递结构的前5个成员。我该怎么做?

最佳答案

如果隐藏在私有封装之后,可以将结构本身声明为任何形式。这将是一个选项:只允许通过setters/getter访问结构。
假设您定义了两个这样的结构:

typedef struct
{
  uint8_t  a;
  uint8_t  b;
  uint8_t  c;
  uint16_t d;
  uint8_t  e;
} foo_write_t;

typedef struct
{
  uint8_t  a;
  uint8_t  b;
  uint8_t  c;
  uint16_t d;
  uint8_t  e;
  uint16_t f;
  uint32_t g;
  uint32_t h;
} foo_read_t;

然后,您可以创建一个新的ADT,其中包含两个重叠的元素。Aunion,例如:
union foo_t
{
  foo_write_t write;
  foo_read_t  read;
  struct                 // C11 anonymous struct
  {
    uint8_t  a;
    uint8_t  b;
    uint8_t  c;
    uint16_t d;
    uint8_t  e;
    uint16_t f;
    uint32_t g;
    uint32_t h;
  };
};

现在上面有三种不同的方法来访问相同的内存。foo.afoo.write.afoo.read.a。但是,foo.write缺少f,g,h。如果我们添加私有封装,我们还可以阻止对foo.a的直接访问。
在C语言中,私有封装是通过不透明类型完成的,头“foo.h”变成如下:
// foo.h
typedef union foo_t foo_t;

typedef struct
{
  uint8_t  a;
  uint8_t  b;
  uint8_t  c;
  uint16_t d;
  uint8_t  e;
} foo_write_t;

typedef struct
{
  uint8_t  a;
  uint8_t  b;
  uint8_t  c;
  uint16_t d;
  uint8_t  e;
  uint16_t f;
  uint32_t g;
  uint32_t h;
} foo_read_t;


foo_t* foo_init(
  uint8_t  a,
  uint8_t  b,
  uint8_t  c,
  uint16_t d,
  uint8_t  e,
  uint16_t f,
  uint32_t g,
  uint32_t h);

void foo_delete (foo_t* foo);

以及相应的c文件:
// foo.c
#include "foo.h"

union foo_t
{
  foo_write_t write;
  foo_read_t  read;
  struct
  {
    uint8_t  a;
    uint8_t  b;
    uint8_t  c;
    uint16_t d;
    uint8_t  e;
    uint16_t f;
    uint32_t g;
    uint32_t h;
  };
};

foo_t* foo_init(
  uint8_t  a,
  uint8_t  b,
  uint8_t  c,
  uint16_t d,
  uint8_t  e,
  uint16_t f,
  uint32_t g,
  uint32_t h)
{
  foo_t* foo = malloc(sizeof *foo);
  if(foo==NULL)
  {
    return NULL;
  }

  foo->a = a;
  foo->b = b;
  foo->c = c;
  foo->d = d;
  foo->e = e;
  foo->f = f;
  foo->g = g;
  foo->h = h;

  return foo;
}

void foo_delete (foo_t* foo)
{
  free(foo);
}

然后可以通过setters/getter提供访问。或者只允许硬拷贝,比如:
void foo_write (foo_t* foo, const foo_write_t* foo_w)
{
  memcpy(foo, foo_w, sizeof foo->write);
}

void foo_read (const foo_t* foo, foo_read_t* foo_r)
{
  memcpy(foo_r, foo, sizeof foo->read);
}

或者允许调用者直接写入ADT,方法是将地址公开并返回到结构的相关部分:
foo_write_t* foo_get_write (foo_t* foo)
{
  return &foo->write;
}

const foo_read_t* foo_get_read (foo_t* foo)
{
  return &foo->read;
}

关于c - 仅访问结构的某些成员,而不是全部访问,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53259385/

10-09 08:59
查看更多