C语言中避免转换格的结构项转换方法
我有以下情况:有一个结构,上面有很多不同类型的数据。还有另一个结构,它有一个整数成员,我在其中放置了与我想要的第一个结构的数据对应的ID。还有第三个结构应该携带这些数据。例如: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; }
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 tolong
不起作用。您可以设计这些元数据,这将是一个有效和高效的解决方案(也是您在C中的唯一选择)。虚拟方法和模板实际上是使用C++语言特征实现这些元数据的。虚拟函数调用的开销(至少在理论上)相当于在类似C的解决方案中获取元数据,相当于在大switch语句中进行分支(假设对switch子句进行了适当的编译器优化)。对不起,但是void*
解决方案确实是解决问题的方法。此外,如何使用单个数组比使用370个变量更大?另外,它看起来应该是DataValue.data=(long)(*pointerArray[MyRequest.data])
,内部带有星号。另一个问题:如果只是将值强制转换为long
,为什么要将值存储在所有不同的数据类型中?如果这是为了保持结构成员列表与开关同步,然后可能会有帮助。你也可以考虑生成C代码。它可能很简单,只需编写几十行脚本(用python、awk或其他语言)来生成包含