我正在编写一个SCPI解析器(作为lib)。 lib用户的设备或应用程序功能需要能够以多种类型输出多个结果(不是混合类型,即A类型的多个结果或类型B的多个结果)。
我首先通过执行控件将一个void指针数组传递给设备函数(如果设备函数类似于unsigned int deviceFunction (double inArg1, bool inArg2, void ** outResults);
),但在这里查看几个Q似乎是无效的ptrs不推荐使用,因为当我的响应格式化程序查看结果数据时,它不知道要转换为什么类型。
我查看了使用联合和结构,类似于https://stackoverflow.com/a/3852192/1292918但是我不确定当设备功能需要报告多个结果时这是否是最佳方式。
也许我刚想到了我的想法。这样做有共同的方式或习惯用法吗?
(注意这是C,不是 C ++)
答案 0 :(得分:2)
根据Eric的评论,我提出了以下代码,它使用union
来返回复杂的结构。在这种情况下,不会出现上面提到的“别名规则”错误。
struct Result {
int type;
};
struct Data1
{
int type;
char* str;
int val;
};
struct Data2 {
int type;
int arr[4];
};
union StructTestUnion
{
struct Result res;
struct Data1 data1;
struct Data2 data2;
};
union StructTestUnion getRandomResult(void) {
static int cnt = 0;
union StructTestUnion resVal;
switch (cnt) {
case 0:
resVal.data1.type = 1;
resVal.data1.str = "struct data 1";
resVal.data1.val = 123;
break;
case 1:
resVal.data2.type = 2;
resVal.data2.arr[0]=1;
resVal.data2.arr[1]=2;
resVal.data2.arr[2]=3;
resVal.data2.arr[3]=4;
break;
}
cnt++;
if (cnt==2) cnt = 0;
return resVal;
}
int main() {
union StructTestUnion resVal;
int a =0;
for (a =0; a<4; a++) {
resVal = getRandomResult();
printf("%d: %d ", a, resVal.res.type);
switch ( resVal.res.type ) {
case 1:
printf("str=[%s] val=[%d]\n", resVal.data1.str, resVal.data1.val);
break;
case 2:
printf("arr=[%d,%d,%d,%d]\n",resVal.data2.arr[0], resVal.data2.arr[1],resVal.data2.arr[2], resVal.data2.arr[3]);
break;
}
}
return 0;
}
答案 1 :(得分:2)
这是一个例子。根据您的喜好或需求,可能会有许多变化:
struct MyStruct
{
enum MyNum { Integer, Float, String } WhatTypeIsHere;
size_t HowMany;
union
{
int Integer;
float Float;
const char *String;
} u[MaximumNumberOfElement];
};
要设置一些x
struct MyStruct
,请设置
x.WhatTypeIsHere = Float;
x.HowMany = NumberOfObjectsThisTime;
for (i = 0; i < NumberOfObjectsThisTime; ++i)
x.u[i].Float = some value;
Integer
或其他类型的设置类似。
阅读:
switch (x.WhatTypeIsHere)
{
case Float;
for (i = 0; i < x.HowMany; ++i)
Use x.u[i].Float for something…;
break;
case Integer:
…
}
您的函数可以声明,以便调用者将struct MyStruct
传递给它,函数填充它,或者函数定义本地struct MyStruct
并按值返回它。 (通常,当你执行后者时,在C的底层实现中发生的是:调用者为struct MyStruct
分配空间并将其地址传递给被调用的函数,该函数负责填充它。如果编译器正确优化,性能等同于第一个选项,即使源代码看起来像被调用函数按值返回结构。)
关于结构和联合的组织方式有多种选择。您可以使用数组联合而不是联合数组,并且可以单独传递有关返回类型的信息而不是结构内的enum
,并且可以单独返回已知元素的数量或者通过一些其他信息,例如数组内的sentinel值。对于小而简单的用途,这些变化可能没有太大区别,它们由您自行决定。
答案 2 :(得分:1)
你仍然可以使用void
双指针,但是你必须找到一种方法来告诉调用者它实际上是什么类型。例如,通过使用return
从函数返回它,或者通过使用另一个引用类型参数,例如int *outResultsType
。
然后将其留给调用者以正确使用数据。
答案 3 :(得分:0)
您可以创建如下通用结构:
struct Generic {
int type;
}
和几个带有数据的实际返回结构,但第一个字段未经修改:
struct Data1 {
int type; // == TYPE_DATA1 == 1
char* aCharVal;
double aDoubleVal;
}
struct Data2 {
int type; // == TYPE_DATA2 == 2
int* anArray;
int arraySize;
}
这样你可以返回结构,将其转换为struct Generic
,检查类型并继续进行。
此方法的一个问题是“取消引用类型 - 惩罚指针将破坏严格别名规则”。