Как назвать хороший / значимый тип? - PullRequest
0 голосов
/ 23 января 2019

Device_Manager.h

typedef enum
{
    DNM = 0x2A,

}TYPE_e;

typedef struct DEVICE_s* p_DEVICE;
typedef p_DEVICE(*FUNC)(char* name, TYPE_e type, uint32_t ip, uint16_t method, uint16_t groupRule);   

p_DEVICE DeviceManager_New(void);
p_DEVICE DeviceManager_Ctor(char* name, TYPE_e type, uint32_t ip, uint16_t method, uint16_t groupRule);
p_DEVICE DeviceManager_Dtor(p_DEVICE element);

Device_Manager.c

struct DEVICE_s
{
    uint32_t IP;
    TYPE_e Type;
    uint16_t Method;
    uint16_t GroupRule;
    char Name[40];
    FUNC fp_Ctor, fp_Dtor;    //this line needs modification
}DeviceSet[32],DeviceTemp;

p_DEVICE DeviceManager_InitObject(p_DEVICE* self)
{
    (*self) = DeviceManager_New();
    (*self)->IP = 0;
    (*self)->Type = 0;
    (*self)->Method = 0;
    (*self)->GroupRule = 0;
    memset((*self)->Name, 0, NAME_SIZE);
    (*self)->fp_Ctor = DeviceManager_Ctor;
    (*self)->fp_Dtor = DeviceManager_Dtor;    // warning: assign to wrong type
    return (*self);
}
p_DEVICE DeviceManager_New(void)
{
    return &DeviceTemp;
}
p_DEVICE DeviceManager_Ctor(char* name, TYPE_e type, uint32_t ip, uint16_t method, uint16_t groupRule)
{
    memcpy(DeviceTemp.Name, name, sizeof(name));
    DeviceTemp.Type = type;
    DeviceTemp.IP = ip;
    DeviceTemp.Method = method;
    DeviceTemp.GroupRule = groupRule;
    return &DeviceTemp;
}
p_DEVICE DeviceManager_Dtor(p_DEVICE element)
{
    element->IP = 0;
    element->Type = 0;
    element->Method = 0;
    element->GroupRule = 0;
    memset(element->Name, 0, NAME_SIZE);
    return element;
}

Я впервые реализую концепцию инкапсуляции и столкнулся с некоторой проблемой.

В заголовочном файлеЯ использовал typedef для определения типа "FUNC" в качестве указателя на функцию.

Я думаю, что это имя "FUNC" недостаточно понятно, потому что такой способ именования приведет к:

struct DEVICE_s
{
    uint32_t IP;
    TYPE_e Type;
    uint16_t Method;
    uint16_t GroupRule;
    char Name[40];
    FUNC1 fp_Ctor;    //not clear
    FUNC2 fp_Dtor;    //not clear
}DeviceSet[32],DeviceTemp;

fp_Ctor и fp_Dtor имеют одинаковый тип (указатель на функцию) и различаются по номеру аргумента.

Я всегда борюсь за тип именования.Можете предложить несколько предложений по типу именования?

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Стиль кодирования ядра Linux предлагает использовать typedefs с осторожностью. «Методы» или указатели на функции обычно группируются в структуру операций. Например:

// DeviceManager.h
//

struct device_operations;

struct device {
    const char *name;
    const struct device_operations *ops;
};

struct device_operations {
    void (*ctor)(struct device *d, const char *name);
    void (*dtor)(struct device *d);
};

struct device *DeviceManager_new(const char *name);


// DeviceManager.c
//

#include <stdlib.h>

static void DeviceManager_ctor(struct device *d, const char *name);
static void DeviceManager_dtor(struct device *d);

static struct device_operations DeviceManager_ops = {
    .ctor = DeviceManager_ctor,
    .dtor = DeviceManager_dtor,
};

struct device *DeviceManager_new(const char *name)
{
  struct device *d = malloc(sizeof(*d));
  if (!d)
    return NULL;

  d->ops = &DeviceManager_ops;
  d->ops->ctor(d, name);

  return d;
}

static void DeviceManager_ctor(struct device *d, const char *name) { /* ... */ }
static void DeviceManager_dtor(struct device *d) { /* ... */ }
0 голосов
/ 23 января 2019

Это все немного субъективно, но я бы начал с того, что отбросил стиль сокрытия указателей за typedef и намазывал на него какую-то «венгерскую нотацию». С этим согласится множество программистов на Си.

Итак, первое предложение состоит в том, чтобы пойти с

typedef struct DEVICE_s DEVICE_s;

А затем определите ваш непрозрачный интерфейс на основе DEVICE_s*. Мало того, что легче читать, вы отфильтровывает запутывание, как вызывающий абонент, пытающийся передать p_DEVICE* пользовательским функциям и т. Д., Потому что они не понимают, что у них уже есть указатель. (Win32 API сильно страдает от этой проблемы.)

Тогда ваш конструктор становится

DEVICE_s* DeviceManager_Ctor ( ...

И все функции-члены получат параметр DEVICE_s*, а не p_DEVICE по значению. Вызывающий должен будет объявлять указатели вместо объектов, давая им понять, что у них есть указатель на неполный тип и с чем они могут / не должны играть.

Далее вы можете удалить указатель, скрытый в указателе функции. Это не проблема, но приятно быть последовательным:

typedef DEVICE_s* DeviceManager_Ctor_t ( ...

Тогда ваши определения указателей на функции станут:

DeviceManager_Ctor_t* Ctor;

Вы можете отказаться от именования "fp", так как уже очевидно, что тип является указателем на функцию.


В качестве примечания я бы рекомендовал избегать имитации функций-членов C ++ с пометкой obj.member. Потому что в C, без указателя this, вы получите obj.member(&obj, ...), что отчасти избыточно.

Скорее просто примите, что C такой, какой он есть, и вызовите функции-члены как DeviceManager_Ctor(obj);, где obj объявлено как DEVICE_s* obj;. Ключом к читаемому OO-коду является использование согласованного префикса исходного кода для всех функций, принадлежащих «классу», как вы уже это делаете: DeviceManager_.

...