C 返回值的类型检查

C 返回值的类型检查,c,types,typeof,C,Types,Typeof,我有一个列表,我想能够把不同的类型。我有一个函数,返回索引处的当前值: void *list_index(const List * list, int index) { assert(index < list->size); return list->data[index]; } 现在,为了从阵列中获取数据: structA *A; structB *B; for(j=0... ) { A = list_index(list, j); B = list_i

我有一个列表,我想能够把不同的类型。我有一个函数,返回索引处的当前值:

void *list_index(const List * list, int index) {
    assert(index < list->size);
    return list->data[index];
}
现在,为了从阵列中获取数据:

structA *A;
structB *B;
for(j=0... ) {
 A = list_index(list, j);
 B = list_index(list, j);
}
但是现在我如何找到返回值的类型呢?typeof(我使用的是GCC btw)可以这样做吗


这是可能的还是我必须做一些不同的构造?

你必须使用如图所示的联轴节。

你必须使用如图所示的联轴节。

你有一些选择。请记住,C基本上不是一种动态类型的语言

为结构创建一个公共基础,并在其中放置一个自己的简单类型指示符

struct base {
  int type_indication:
};
然后


然后您可以将指针强制转换为
(struct base*)

您有一些选择。请记住,C基本上不是一种动态类型的语言

为结构创建一个公共基础,并在其中放置一个自己的简单类型指示符

struct base {
  int type_indication:
};
然后


然后可以将指针强制转换为
(struct base*)

解决此问题的最佳方法是使用联合

另一种方法是将列表项memcpy()复制到适当类型的实际结构(即,不是指针)。这样做的好处是使每个列表项尽可能小

第三种方法是只强制转换指针类型,如中所示。只要对象使用正确的类型或字符取消引用,C就允许这样做

无论哪种方式,您都需要在每个结构中放置一个代码来标识对象的类型。编译器无法找出指针指向的对象。即使你可以使用
typeof
,你也不应该。不是C99

从技术上讲,如果您不使用联合,您将无法通过合法的C99访问类型代码,因为您需要对类型进行临时假设,这将违反必须通过联合或字符*将对象作为其实际类型取消引用的规则。然而,由于类型代码必须在每种类型中处于相同的位置(为了有用),因此这种常见的违反标准的技术行为实际上不会在实践中导致别名优化错误

实际上,如果您将类型代码设置为
char
,将其作为结构中的第一件事,并通过
char*
访问它,我认为您最终将得到的代码有点难以理解,但完全符合C99

下面是一个例子,它传递了
gcc-Wall-Wextra

#include <stdio.h>
#include <stdlib.h>

struct A {
    char typeCode;
    int something;
};
struct B {
    char typeCode;
    double somethingElse;
};

void *getMysteryList();

int main()
{
    void **list = getMysteryList();
    int i;
    for (i = 0; i < 2; ++i)
        switch (*(char *) list[i]) {
        case 'A':
            printf("%d\n", ((struct A *) list[i])->something);
            break;
        case 'B':
            printf("%7.3f\n", ((struct B *) list[i])->somethingElse);
            break;
        }
    return 0;
}

void *getMysteryList()
{
    void **v = malloc(sizeof(void *) * 2);
    struct A *a = malloc(sizeof(struct A));
    struct B *b = malloc(sizeof(struct B));

    a->typeCode = 'A';
    a->something = 789;
    b->typeCode = 'B';
    b->somethingElse = 123.456;

    v[0] = a;
    v[1] = b;
    return v;
}
#包括
#包括
结构A{
字符类型码;
智力的东西;
};
结构B{
字符类型码;
双重的东西;
};
void*getMysteryList();
int main()
{
void**list=getMysteryList();
int i;
对于(i=0;i<2;++i)
开关(*(字符*)列表[i]){
案例“A”:
printf(“%d\n”)((结构A*)列表[i])->某物;
打破
案例“B”:
printf(“%7.3f\n”,((结构B*)列表[i])->somethingElse);
打破
}
返回0;
}
void*getMysteryList()
{
void**v=malloc(sizeof(void*)*2);
结构A*A=malloc(sizeof(结构A));
结构B*B=malloc(sizeof(结构B));
a->typeCode='a';
a->something=789;
b->typeCode='b';
b->somethingElse=123.456;
v[0]=a;
v[1]=b;
返回v;
}

解决这一问题的最佳方法是使用联合体

另一种方法是将列表项memcpy()复制到适当类型的实际结构(即,不是指针)。这样做的好处是使每个列表项尽可能小

第三种方法是只强制转换指针类型,如中所示。只要对象使用正确的类型或字符取消引用,C就允许这样做

无论哪种方式,您都需要在每个结构中放置一个代码来标识对象的类型。编译器无法找出指针指向的对象。即使你可以使用
typeof
,你也不应该。不是C99

从技术上讲,如果您不使用联合,您将无法通过合法的C99访问类型代码,因为您需要对类型进行临时假设,这将违反必须通过联合或字符*将对象作为其实际类型取消引用的规则。然而,由于类型代码必须在每种类型中处于相同的位置(为了有用),因此这种常见的违反标准的技术行为实际上不会在实践中导致别名优化错误

实际上,如果您将类型代码设置为
char
,将其作为结构中的第一件事,并通过
char*
访问它,我认为您最终将得到的代码有点难以理解,但完全符合C99

下面是一个例子,它传递了
gcc-Wall-Wextra

#include <stdio.h>
#include <stdlib.h>

struct A {
    char typeCode;
    int something;
};
struct B {
    char typeCode;
    double somethingElse;
};

void *getMysteryList();

int main()
{
    void **list = getMysteryList();
    int i;
    for (i = 0; i < 2; ++i)
        switch (*(char *) list[i]) {
        case 'A':
            printf("%d\n", ((struct A *) list[i])->something);
            break;
        case 'B':
            printf("%7.3f\n", ((struct B *) list[i])->somethingElse);
            break;
        }
    return 0;
}

void *getMysteryList()
{
    void **v = malloc(sizeof(void *) * 2);
    struct A *a = malloc(sizeof(struct A));
    struct B *b = malloc(sizeof(struct B));

    a->typeCode = 'A';
    a->something = 789;
    b->typeCode = 'B';
    b->somethingElse = 123.456;

    v[0] = a;
    v[1] = b;
    return v;
}
#包括
#包括
结构A{
字符类型码;
智力的东西;
};
结构B{
字符类型码;
双重的东西;
};
void*getMysteryList();
int main()
{
void**list=getMysteryList();
int i;
对于(i=0;i<2;++i)
开关(*(字符*)列表[i]){
案例“A”:
printf(“%d\n”)((结构A*)列表[i])->某物;
打破
案例“B”:
printf(“%7.3f\n”,((结构B*)列表[i])->somethingElse);
打破
}
返回0;
}
void*getMysteryList()
{
void**v=malloc(sizeof(void*)*2);
结构A*A=malloc(sizeof(结构A));
结构B*B=malloc(sizeof(结构B));
a->typeCode='a';
a->something=789;
b->typeCode='b';
b->somethingElse=123.456;
v[0]=a;
v[1]=b;
返回v;
}

使要放入列表的元素都从公共基类继承。然后,您可以让基类包含标识实际类型的成员

class base {
public:
  typedef enum {
    type1,
    type2,
    type3
  } realtype;

  virtual realtype whatAmI()=0;
};

class type_one : public base {
  public:
    virtual base::realtype whatAmI() { return base::type1; };
};

class type_two : public base {
  public:
    virtual base::realtype whatAmI() { return base::type2; };
};
之后,您将声明列表类型,如下所示:

std::list<base *> mylist;
std::list mylist;
一个
typedef struct structA { int tag; List *x; char *y; List *z; } structA;
typedef struct structB { int tag; List *u; char *w; } structB;
enum tags { structAtype, structBtype };
void *elem = list_index(list, index)
switch (*(int *)elem) {
case structAtype:
    /* elem is a structA */
              :
case structBtype:
    /* elem is a structB */