C函数有多种类型的多个结果

时间:2013-05-20 12:23:51

标签: c pointers void-pointers

我正在编写一个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 ++)

4 个答案:

答案 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,检查类型并继续进行。

此方法的一个问题是“取消引用类型 - 惩罚指针将破坏严格别名规则”。