【问题标题】:Different struct types between system versions. This is a stumper系统版本之间的不同结构类型。这是一个笨蛋
【发布时间】:2012-02-24 07:36:01
【问题描述】:

我正在对 iPhone 进行调整,我需要读取和修改结构的内容。但是,iOS 4.1、iOS 4.2 和 iOS 5 之间的结构定义是不同的,我希望保持与所有这些的兼容性。问题不在于我做不到;问题是,对于每个碰巧改变结构的 iOS 更新,我必须重写 100 多行完全相同的代码是没有意义的。

我没有在没有任何上下文的情况下实际发布项目的源代码,而是写了一个简化的示例问题。这篇文章有点太长了,所以我把它放在了 Pastie 上:http://pastie.org/3295629 问题的所有细节都作为 cmets 包含在那个 Pastie 中。

提前感谢您提供的任何帮助。我完全被难住了。

(如果您想查看我在 iOS 项目中处理的实际结构:http://pastie.org/3296564

【问题讨论】:

  • 如果您告诉我们原始结构是什么,它实际上可能会有所帮助。我们可能比您发明的人为问题更容易帮助您解决原始问题。 (或者我们可能不会。)
  • 我刚刚编辑了问题并添加了指向结构的链接。

标签: c struct type-conversion


【解决方案1】:

听起来你应该隐藏对接口后面结构的访问。你说的100多行代码不应该直接使用真正的结构,而是接口。

例如,如果两个不同的版本是这样的:

struct foo_v1 {
    int a;
    int b;
    long long c;
};

struct foo_v2 {
    int a;
    char x;
    int d;
};

你围绕这个包装一个接口:

struct abstract_foo {
    int version;
    int a;
    int b;
    long long c;        
    char x;
    int d;
};

struct astract_foo get_foo(void);
void set_foo(struct abstract_foo f);

get_foo()set_foo() 分别在原始结构和接口结构之间复制。版本字段设置为 1 或 2,因此使用此结构的代码可以决定使用哪些字段。

此示例使用结构的副本。这很简单,适用于简单的结构(如文件信息)。您还可以设计一个使用指针而不是复制值的接口结构,例如:

struct abstract_foo {
    int version;
    int *a;
    int *b;
    long long *c;        
    char *x;
    int *d;
};

这些只是示例,在 C 中进行抽象的方法有一百万种。

【讨论】:

  • 这很有趣。我将尝试实现这一点。
【解决方案2】:

我不熟悉 iOS 开发,但似乎最自然的方法是编译三个不同的可执行文件,每个版本的 iOS 一个。该结构应该在 iOS 提供的某个头文件中定义,但如果不是,那么您可以使用 #ifdefs 来确定您正在编译的 iOS 版本并自己定义。

#if IOS == 4_1
typedef struct osdata {
int dengus, payness, fibbus;
} mydata;
#elsif IOS == 4_2
typedef struct osdata {
int dengus, payness, chonus, fibbus;
} mydata;
#endif

如果由于某种原因无法做到这一点(例如,Apple 要求所有操作系统都有一个可执行文件),那么您必须做一些更复杂的事情。我想我会创建自己的结构,称为mydata,我可以在我的大部分源代码中使用它。当我需要与操作系统交互时,我会使用一些不同的函数将其转换为正确的字节流,以便该特定版本的操作系统识别,或者将其从操作系统的结构转换为我的结构。通过这样做,您可以抽象出操作系统中的差异,并使您可以在大多数代码中只使用一种数据结构。

【讨论】:

    【解决方案3】:

    最简洁的方法可能是使用函数指针。这些函数(每个版本一个)接收一个 void* 指针(可能更多)并将该指针转换为适当的结构,然后执行它们的工作。智能工会也是一种可能。

    避免函数指针,你也可以做类似的事情

    switch (ver=get_version()) {
    case 1: return do_version_1_stuff(ptr, 1,2,3);
    case 2: return do_version_2_stuff(ptr, 1,2,3);
    case 3: return do_version_3_stuff(ptr, 1,2,3);
    default: fprintf(stderr, "Unknown version %d, call QC!\n", ver);
           return -1;
    }
    

    更新:(“智能联合”似乎没有很好的定义)

    智能联合是类型的联合(在大多数情况下是结构),它们具有相同的目的,但具有更多或更少的相似布局。 union 包含一个 type-member,由所有 union-members 共享,用于选择合适的成员。

    struct aaaa {
        int type;
        float value;
        };
    
    struct bbbb {
        int type;
        float value;
        char *description;
        };
    
    union a_or_b {
       struct aaaa a;
       struct bbbb b;
       };
    

    如果成员不共享一个共同的第一个类型字段,则可以将类型字段放在联合之外的包装结构中:

    struct kkkk {
        float value;
        };
    struct llll {
        float value;
        char *description;
        };
    
    struct k_or_l {
       int type;
       union {
           struct kkkk k;
           struct llll l;
           } u;
       };
    
    union a_or_b *abp;
    struct k_or_l *klp;
    

    对 union 中内容的引用现在将通过 abp->a.valueklp->u.k.value,例如

    int value = abp->a.type==1 ?  abp->a.value : abp->b.value;
    

    或者,甚至更好,使用switch (abp->type) {}

    【讨论】:

    • 我在 Google 上搜索了 smart union,没有找到与编程相关的链接。
    • GIYF:“智能联合算法”。再想一想,智能联合并不适合,因为结构布局不同,因此结构不能重叠。
    • 现在我找到了计算 sets 的 union 的结果, 这是完全不相关的。
    • @wildplasser 如果它仍然与问题相关,您能否扩展智能联盟?我自己对这个概念并不熟悉,而且像 Dietrich 一样很难弄清楚你在做什么。
    • 我很惊讶你不知道这个概念。谷歌似乎很困惑,似乎没有多大帮助,对不起。也许这是一个unixism。我会修改的。
    猜你喜欢
    • 2017-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-11
    相关资源
    最近更新 更多