Доступ только к определенным членам структуры и не ко всем - PullRequest
0 голосов
/ 12 ноября 2018

В настоящее время у меня есть структура с 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;

Существует два варианта использования этой структуры: чтение и запись, когда чтение использует все 8 членов, а запись использует только первые 5 (a-e).

В настоящее время я разбил это на две отдельные структуры, одну для чтения (с 8 членами) и одну для записи (с 5 членами), однако было предложено, чтобы я мог использовать одну структуру для обоих, и при передаче необходимых членов для функции «запись» для доступа только к первым 5 элементам.

if(x == y){ 
    BarRead(&readStruct);
} else {
    BarWrite(&writeStruct);
}

Вместо того, чтобы передавать readStruct и writeStruct, я хочу использовать только одну структуру, genericStruct. Для условия if я могу просто передать &genericStruct, и это будет работать нормально, однако я не знаю, что передать в условии else.

Я просто хочу передать первые 5 членов структуры в условии else. Как мне это сделать?

Ответы [ 2 ]

0 голосов
/ 12 ноября 2018

Вы можете создать typedef для структуры, которая содержит только от a до e. Затем вы можете определить функцию «вставки данных», которая принимает в качестве аргумента указатель на этот тип структуры. Что-то вроде

void Insert_Data(aToEStruct *data);

Каждый раз, когда вы хотите записать в структуру, вы используете только эту функцию.

0 голосов
/ 12 ноября 2018

Вы можете объявить саму структуру как угодно, если вы скрываете ее за частной инкапсуляцией. Это будет один из вариантов: разрешить доступ к структуре можно только через сеттеры / геттеры.

Предположим, вы определили две структуры следующим образом:

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, содержащий оба элемента с перекрывающимися элементами. A union, например:

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

Выше теперь есть 3 разных способа доступа к одной и той же памяти. foo.a, foo.write.a или foo.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);
}

Тогда вы можете предоставить доступ через сеттеры / геттеры. Либо разрешив только печатные копии, что-то вроде этого:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...