2

我有几个硬件信号可以根据与可以切换各个信号的场景相关的属性进行切换。问题是信号和定义场景的属性,这三者都可能改变。我不得不考虑基于模块化框架的设计,其中有SignalManager处理信号创建的,还有一个SignalPropertiesDataSignalPropertiesDataManager特定SignalScenario结构相关联的,所有这些都是专门为任何类型的信号创建的SignalManager。我希望遵循 C 编程范式中的公共接口和私有数据。

当涉及到类型安全和此类问题时,我的困境通常是 C,唯一的解决方案是失去类型安全性并对任何和所有类型的数据使用“void”。你能指出我在浩瀚的开源海洋中的任何代码或组件,它可以作为这个问题的正确参考。

信号管理器.h:

#ifdef _SIGNAL_MANAGER_H
#define _SIGNAL_MANAGER_H

int createSignal(SignalDescPtr signalDescPtr);

int destroySignal();

typedef struct SignalDesc* SignalDescPtr;

#endif

信号管理器.c:

#include "signal_manager.h"

typedef struct {
  char* signalName;
  unsigned int signalId;
  SignalPropertiesDataPtr signalProperties;
} SignalDesc;

signal_properties_data.h:

#ifdef _SIGNAL_PROPERTIES_DATA
#define _SIGNAL_PROPERTIES_DATA

typedef enum {
  SIGNAL_DATA_INT_TYPE,
  SIGNAL_DATA_UNSIGNED_INT_TYPE,
  SIGNAL_DATA_FLOAT_TYPE,
     :
  SIGNAL_DATA_UNSPECIFIED_BASIC_TYPE
} eSignalBasicType;

typedef enum {
  SIGNAL_DATA_LIST_ARRAY_TYPE,
  SIGNAL_DATA_LIST_ADT_TYPE,
   :
   :
  SIGNAL_DATA_LIST_UNSPECIFIED_TYPE
} eSignalComplexType

typdef  union {
  eSignalBasicType signalBasicType;
  eSignalComplexType signalComplexType;
} eSignalType;

typedef struct {
  eSignalType signalType;
  unsigned int signalDataLen;
} SignalDataValueType;    

typedef SignalPropertiesData* SignalPropertiesDataPtr;

result_t setSignalType(..);
result_ getSignalType(..);
result_t setSignalData(..);
result_t getSignalData(..);
result_t setSignalDataLen(..);
result_t getSignalDataLen(..);

#endif

signal_properties_data.c:

#include "signal_properties_data.h"

typdef struct {
  SignalDataValueType signalPropertiesDataType;
  void* signalPropertiesDataValue;
} SignalPropertiesData;

signal_properties_data_mgr.h:

#ifdef _SIGNAL_PROPERTIES_DATA_MGR_H
#define _SIGNAL_PROPERTIES_DATA_MGR_H

#include "signal_properties_data.h"
#include "signal_scenario.h"

typedef SignalScenarioDesc* SignalScenarioDescPtr;

result_t createSignalPropertiesData(SignalPropertiesDataPtr *signalPropDataPtr, eSignalType desiredSignalType);

result_t freeSignalPropertiesData(..);

result_t associateSignalToggleScenario(SignalPropertiesDataPtr *signalPropDataPtr, SignalScenPtr signalScenPtr);

result_t disassociateSignalToggleScenario(SignalPropertiesDataPtr *signalPropDataPtr, SignalScenarioDescPtr signalScenPtr);

#endif 

signal_properties_data_mgr.c:

#include "signal_properties_data_mgr.h"

typedef struct {
  toggleFuncPtr fptr;
} SignalScenarioDesc;
4

2 回答 2

0

避免去void *。它失去了原型的好处并且没有必要,

因为这是 C,你应该写signalmanager.h

#ifndef SIGNAL_MANAGER_H_INCLUDED
#define SIGNAL_MANAGER_H_INCLUDED

typedef struct SignalDesc* SignalDescPtr;

int createSignal(SignalDescPtr signalDescPtr);

int destroySignal(void);

#endif

变化:

  1. 批判:成语是#ifndef MACRO / #define MACRO / #endif。你用#ifdef了哪个不行。
  2. 在使用之前放置 typedef。
  3. 添加显式(void)以制作destroySignal(void)原型。您的版本只是说“有一个函数destroySignal()返回一个int但它需要一个未指定(但不是可变参数)的参数列表”。
  4. 不要将保留的名称空间(前导下划线、大写字母)用于标头保护保护。

我不想在数据类型 typedef 中隐藏指针,所以我可能会写:

#ifndef SIGNAL_MANAGER_H_INCLUDED
#define SIGNAL_MANAGER_H_INCLUDED

typedef struct SignalDesc SignalDesc;

extern int createSignal(SignalDesc *sigdesc);

extern int destroySignal(void);

#endif /* SIGNAL_MANAGER_H_INCLUDED */

我不确定创建和销毁的接口是否正确,但这是另一个需要讨论的主题。我通常希望发现接口更像:

extern SignalDesc *createSignal(const char *name, int signum);
extern void destroySignal(SignalDesc *sigdesc);

然后,实现文件signal_manager.c将定义结构类型并使用它;外部接口是通过使用指针的函数来实现的。

#include "signal_manager.h"
#include "signal_properties_data.h"

struct SignalDesc
{
    char                 *signalName;
    unsigned int          signalId;
    SignalPropertiesData *signalProperties;
};

需要类似的signal_properties_data.h清理:

#ifndef SIGNAL_PROPERTIES_DATA_H_INCLUDED
#define SIGNAL_PROPERTIES_DATA_H_INCLUDED

typedef enum {
  SIGNAL_DATA_INT_TYPE,
  SIGNAL_DATA_UNSIGNED_INT_TYPE,
  SIGNAL_DATA_FLOAT_TYPE,
     :
  SIGNAL_DATA_UNSPECIFIED_BASIC_TYPE
} eSignalBasicType;

typedef enum {
  SIGNAL_DATA_LIST_ARRAY_TYPE,
  SIGNAL_DATA_LIST_ADT_TYPE,
   :
   :
  SIGNAL_DATA_LIST_UNSPECIFIED_TYPE
} eSignalComplexType

typdef  union {
  eSignalBasicType signalBasicType;
  eSignalComplexType signalComplexType;
} eSignalType;

typedef struct {
  eSignalType signalType;
  unsigned int signalDataLen;
} SignalDataValueType;

/* Huge hole in types here - or is SignalValueDataType what you're after? */
typedef struct SignalPropertiesData SignalPropertiesData;

result_t setSignalType(..);
result_t getSignalType(..);
result_t setSignalData(..);
result_t getSignalData(..);
result_t setSignalDataLen(..);
result_t getSignalDataLen(..);

#endif  /* SIGNAL_PROPERTIES_DATA_H_INCLUDED */

这个修改后的标题还不是独立的。它没有定义result_t,所以它应该包含定义的标题。我假设...函数调用中的符号是“不想在这个问题中指定”,因为它在 C 中无效;在指定省略号之前,您必须有一个已知类型的参数。

从标头中的函数不清楚为什么标头的用户需要了解其中定义的类型。将标头视为将被共享的资源。它“属于”或描述文件(或一小组文件)的外部接口。它为用户提供了使用代码提供的设施所需的最少数据,但不会超过最低限度。您有时会发现一组实现工具的文件需要在它们之间共享私有标头以及其他代码(“客户”代码或“消费者”代码)使用的公共标头。

不透明类型的关键是消费者不需要知道结构的内部细节就能够使用指向结构类型的指针(请参阅C 标准的哪个部分允许此代码编译?C 标准是否考虑一下这个头文件中有一种或两种struct uperms_entry类型吗?以及如何在 C 中构造头文件以获得更多见解)。

于 2012-10-21T01:20:38.173 回答
0

我不确定我是否完全理解您的需求,但我认为您可以查看WIN32 句柄以获取参考实现。

一个简短的示例是定义一个宏,让您可以像这样定义自定义句柄:

/* example.h */

#ifndef _EXAMPLE_H
#define _EXAMPLE_H

/* Define macro */
#define DECLARE_HANDLE(HandleName) typedef struct HandleName##Tag * HandleName

/* Declare some handles */
DECLARE_HANDLE(SomeHandle);
DECLARE_HANDLE(SomeOtherHandle);

#endif /* _EXAMPLE_H */

/* example.c */

#include "example.h"

struct SomeHandleTag {
    int foo;
};

struct SomeOtherHandleTag {
    int foo;
};
于 2012-10-21T01:22:04.313 回答