代码之家  ›  专栏  ›  技术社区  ›  user206268

C:元素大小不同的数组

  •  0
  • user206268  · 技术社区  · 15 年前

    是否可以有一个元素(结构)数组,其中的值大小不同?

    我面临的问题是,我不知道如何访问元素,因为它需要强制转换。“array”只包含指向结构的指针。因此,我决定选择void**。由于不是每个元素都属于同一类型,因此也需要将该类型存储在数组中,这样我就可以知道在不进行粗略猜测的情况下将其强制转换为什么类型。不过,这听起来不是很有效。没有更有效的方法吗?

    5 回复  |  直到 15 年前
        1
  •  6
  •   Pete Kirkham    15 年前

    如果不喜欢强制转换,则可以始终使用联合(以及一个标志来指示应将联合解释为哪种类型)

    #include <stdio.h>
    
    typedef struct {
        int a;
    } A;
    
    typedef struct B {
        double b;
    } B;
    
    typedef struct C {
        char c[20];
    } C;
    
    typedef enum {
        TypeA,
        TypeB,
        TypeC,
    } type;
    
    typedef struct {
        type type;
        union { A*a; B*b; C*c; } p;
    } TypedPointer ;
    
    void foreach (TypedPointer* list, void (*fn)(TypedPointer))
    {
        while (list->p.a) {
            fn(*list);
            ++list;
        }
    }
    
    void print_member (TypedPointer ptr)
    {
        switch (ptr.type) {
            case TypeA: printf("A (%d)\n", ptr.p.a->a); break;
            case TypeB: printf("B (%f)\n", ptr.p.b->b); break;
            case TypeC: printf("C (%s)\n", ptr.p.c->c); break;
        }
    }
    
    int main ()
    {
        A a = { .a = 42 };
        B b = { .b = 1.01 };
        C c = { .c = "Hello World!" };
    
        TypedPointer ptrs[] = {
            { .type = TypeA, .p.a = &a },
            { .type = TypeB, .p.b = &b },
            { .type = TypeC, .p.c = &c }, 
            { .type = 0, .p.a = 0} };
    
        foreach(ptrs, print_member);
    
        return 0;
    }
    
        2
  •  10
  •   Jonathan Leffler    15 年前

    不,在C语言中,数组的每个元素都必须是相同的类型(因此大小也相同)。

    您可能需要添加另一个抽象层,在这种情况下,您需要用元素所具有的类型来注释元素,例如,您可以使一个结构数组看起来像:

    enum ElemType {
      TypeNull,
      TypeFoo,
      TypeBar
    ];
    
    struct Elem {
     enum ElemType type;
     void *realElem;
    };
    

    您必须使用插入的实际类型更新“type”,并在读取数组时对此做出决定,然后在“realeem”成员中存储指向实际元素的指针。

    struct Elem arr[42];
    ...
    switch(arr[k].type) {
      case TypeFoo:
         handleFoo(arr[k].realElem);
         break;
      ...
    }
    
        3
  •  2
  •   wilhelmtell    15 年前

    不,C数组的大小是常量,必须在编译时知道。但您可以通过使用指针和动态分配来绕过这个问题。

    这里的问题不是效率而是类型安全。强制转换没有运行时性能成本,它只是一种与编译器对话的机制,要求它“信任您”,并假设在一系列位后面有某种类型。我们谈论的是安全,因为如果你错了,那么任何事情都可能在运行时发生。

    在C(静态语言)中,不可能构造不同类型的数组。您所能做的是构造一个特定结构的数组,但该结构保留指向不同大小对象的指针。例如,让结构保持 char* 指针,在这种情况下,每个对象都持有一个或另一个长度的字符串,因此具有可变大小(以运行时使用的总内存计,而不是以使用的连续空间计)。

    如果您希望这些对象中的每一个 表现 与其他方法不同,您可以使用函数指针数组来模拟多态性,然后根据需要向指向任何函数的结构添加函数指针。

        4
  •  0
  •   rzrgenesys187    15 年前

    强制转换并不是低效的,因为它们只是告诉计算机如何解释内存区域。当编译到程序集时,编译器将创建程序集,根据需要解释内存区域。

        5
  •  0
  •   S.Lott    15 年前

    为此,我们使用指向实际对象的指针数组。

    指针的大小都相同。

    它们指向的对象可以是不同的大小。

    一个“歧视性联盟”对此很有效。

    typedef struct { ... } this_type;
    typedef struct { ... } that_type;
    typedef struct { 
         int subtype;
         union {
             this_type this;
             that_type that
         }
    } discriminated_union;
    

    数组指针指向 discriminated_union 效果很好。