C语言中避免转换格的结构项转换方法

C语言中避免转换格的结构项转换方法,c,algorithm,switch-statement,C,Algorithm,Switch Statement,我有以下情况:有一个结构,上面有很多不同类型的数据。还有另一个结构,它有一个整数成员,我在其中放置了与我想要的第一个结构的数据对应的ID。还有第三个结构应该携带这些数据。例如: struct MyData { char data1; float data2; short data3; //... }; struct MyRequest { int desiredDataId; }; struct DataValue { long data; }

我有以下情况:有一个结构,上面有很多不同类型的数据。还有另一个结构,它有一个整数成员,我在其中放置了与我想要的第一个结构的数据对应的ID。还有第三个结构应该携带这些数据。例如:

struct MyData
{
    char data1;
    float data2;
    short data3;
    //...
};

struct MyRequest
{
    int desiredDataId;
};

struct DataValue
{
    long data;
};
在系统中,我向它的一部分发送一条消息,其中有一个MyRequest,告诉我“我想要数据X”。然后,系统应查看请求的Id对应的对应缓冲区(MyData成员);然后创建一个数据值,并将所需数据(casted)放入
data
成员

要点:系统根据MyRequest的Id识别被请求的MyData成员中的哪一个,最明显的方法是使用开关盒:

switch(MyRequest.desiredDataId)
{
    case 0: //Id correspondent to data1
        DataValue.data = (long) MyData.data1;
        break;
    case 1: //Id correspondent to data2
        DataValue.data = (long) MyData.data2;
        break;
    case 3: //Id correspondent to data3
        DataValue.data = (long) MyData.data1;
        break;
    //...
}
问题是:当MyData中的成员数量很小时,这是很好的;但我需要一个非常大的MyData解决方案——目前,一个拥有370个成员的解决方案,这将导致一个巨大的交换案例——370个案例

问题是:有没有其他方法可以使用更少的编码来进行这种映射

目前,我认为的另一种选择是创建一个
void*
数组,将指针映射到MyData(在我的例子中是全局声明的)。所以,我需要先设置一个巨大的数组,然后调用

DataValue.data = *(long)pointerArray[MyRequest.data]
问题是,尽管避免了巨大的切换情况,但现在我必须面对巨大的数组初始化,因此不是“主解决方案”

还有其他可行的选择吗


注意:请原谅我写了一个错误的C语法;我急于写下这个问题:)

您的问题似乎是一个典型的情况,使用像哈希表一样的键/值存储(在c语言中有例如and),其中MyRequest.data(又称MyRequest.desiredDataId)是键,DataValue.data是值。使用void指针的解决方案几乎是最简单的实现:因为所有键都是整数,所以hash函数就是identity函数

我不知道你为什么要寻找另一种选择,但如果是速度,你确实找到了比哈希表更快的东西,我相信全世界都想知道。我认为您的void*解决方案的速度是最快的(我希望您实际上并没有使用char、int和float,但这些只是示例,并且长强制转换是类似序列化例程的抽象形式—如果不需要长数组,则在赋值时强制转换,并保存间接寻址)


但是,正如我猜想的那样,如果您不想在实现和维护数据结构方面遇到麻烦,那么您应该能够使用哈希表获得一个相对快速的解决方案。

假设满足以下要求:

  • struct MyData
    必须具有针对每个字段的不同类型的所有数据字段
  • MyRequest::desiredDataId
    标识连续范围内的数据字段,或者至少具有可以用伪字段填充的非常小的间隙
  • 请求必须返回
    struct DataValue
    ,字段值在
    DataValue::data
    中转换为
    long
  • 代码不得重复
  • 我建议采取以下措施:

    class DataField {
    public:
        virtual ~DataField() {}
        virtual long toLong() const = 0;
    };
    
    // Wrapper for T that implements toLong()
    template <typename T>
    class DataFieldImpl : public DataField {
    public:
        DataFieldImpl() = default;
        DataFieldImpl(T v) : value(v) {} // implicit construction from T
        DataFieldImpl& operator=(T v) {  // direct assignment from T
            value = v;
            return *this;
        }
        operator T() const     {return value;} // implicit conversion to T
        const T& value() const {return value;} // const accessor
        T& value()             {return value;} // mutable accessor
    
        virtual long toLong() const {
            return static_cast<long>(value);
        }
    
    private:
        T value;
    };
    
    struct MyData {
        static const size_t N = 370;
        DataField* data[N];
    
        // Implement constructor and destructor to create and destroy the fields.
    } myData;
    
    void doRequest(const MyRequest& request, DataValue* response) {
        if (request.desiredDataId < MyData::N) {
            response->data = myData.data[request.desiredDataId].toLong();
        }
    }
    
    类数据字段{
    公众:
    虚拟~DataField(){}
    虚长toLong()常量=0;
    };
    //实现toLong()的T的包装器
    模板
    类DataFieldImpl:公共数据字段{
    公众:
    DataFieldImpl()=默认值;
    DataFieldImpl(tv):值(v){}//从T隐式构造
    DataFieldImpl&运算符=(tV){//来自T的直接赋值
    值=v;
    归还*这个;
    }
    运算符T()常量{返回值;}//到T的隐式转换
    const T&value()const{return value;}//const访问器
    T&value(){return value;}//可变访问器
    虚拟长toLong()常量{
    返回静态_cast(值);
    }
    私人:
    T值;
    };
    结构MyData{
    静态常数大小N=370;
    数据字段*数据[N];
    //实现构造函数和析构函数来创建和销毁字段。
    }我的数据;
    void doRequest(常量MyRequest和request,数据值*响应){
    if(request.desiredDataIddata=myData.data[request.desiredDataId].toLong();
    }
    }
    

    关于“流行的”
    void*
    解决方案:您不能将
    void
    转换为
    long
    。这将需要关于每个字段的元数据信息,指示每个字段的类型以及如何将每个
    void*
    转换为
    long
    ,因为简单的
    operator*
    后跟cast to
    long
    不起作用。您可以设计这些元数据,这将是一个有效和高效的解决方案(也是您在C中的唯一选择)。虚拟方法和模板实际上是使用C++语言特征实现这些元数据的。虚拟函数调用的开销(至少在理论上)相当于在类似C的解决方案中获取元数据,相当于在大switch语句中进行分支(假设对switch子句进行了适当的编译器优化)。

    对不起,但是
    void*
    解决方案确实是解决问题的方法。此外,如何使用单个数组比使用370个变量更大?另外,它看起来应该是
    DataValue.data=(long)(*pointerArray[MyRequest.data])
    ,内部带有星号。另一个问题:如果只是将值强制转换为
    long
    ,为什么要将值存储在所有不同的数据类型中?如果这是为了保持结构成员列表与开关同步,然后可能会有帮助。你也可以考虑生成C代码。它可能很简单,只需编写几十行脚本(用python、awk或其他语言)来生成包含