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

在不破坏现有代码的情况下向结构中添加字段

  •  3
  • Jacob  · 技术社区  · 16 年前

    因此,我正在使用这个庞大的代码库,并意识到其中一个结构缺少一个重要字段。我尽可能仔细地查看了代码(使用结构),得出结论,添加一个额外的字段不会破坏它。

    你知道我会把事情搞砸吗?

    欢迎提供设计建议-我能做到这一点的最佳方式是什么?

    例如。 (如果我不清楚的话):

    typedef struct foo
    {
      int a;
      int b;
    }
    foo;
    

    typedef struct foo
    {
      int a;
      int b;
      int c;
    }
    foo;
    
    10 回复  |  直到 16 年前
        1
  •  4
  •   wheaties    16 年前

    从你上面写的我看不出有什么不对。我能想到两件事:

    1. 无论何时更改代码和重新编译,都会引入查找“隐藏”bug的功能。也就是说,新数据结构中的未初始化指针可能大到足以损坏。
    2. c

    跟进:

    既然你还没有找到错误,我就不再看你的结构了。有人曾经写过“先找马,后找斑马”。也就是说,这个错误可能不是一个奇异的错误。您在单元测试中有多少覆盖范围?我假设这是遗留代码,几乎总是意味着0%,或者至少这是我的经验。这准确吗?

        2
  •  6
  •   Tom Neyland    16 年前

    如果该结构在任何地方被序列化/反序列化,请务必注意代码的该部分。

    仔细检查分配内存的代码区域。

        3
  •  4
  •   Jay    16 年前

        4
  •  2
  •   dirkgently    16 年前

    没有什么。一切。这完全取决于如何、在何处以及为什么使用它。

    假设您所讨论的这个结构是一个C风格的POD,并且代码是最简单的,那么您就可以不受惩罚了。但是,当您尝试更雄心勃勃的事情时,您至少要处理对齐问题(取决于创建对象的方式和位置)和填充。如果这是C++,你的POD包含自定义操作符/ Ccor等,那么你就陷入了很多麻烦。如果您依赖endianness等,可能会出现跨平台问题。

        5
  •  2
  •   Colin    16 年前

    如果代码有一组健壮的单元测试,那么追踪问题可能会容易得多(您征求了设计建议;)

    我假设在这个庞大的代码库中,您不需要在任何地方都使用新的“c”变量,您只是添加它,以便在添加或修改的代码中使用它?您可以创建一个新的结构bar,它包含一个foo对象和c,而不是将c添加到foo中。然后在需要的地方使用酒吧。

    至于真正的bug,它可能是任何信息很少的东西,但是如果我不得不猜测,我会说有人在某处使用了一个神奇的数字而不是sizeof()。

        6
  •  1
  •   Thomas Matthews    16 年前

    memcpy, memset, memcmp . 这些功能不是针对成员的。如果使用的是以前的结构长度,则可能会出现问题。

    还可以在文件中搜索 struct #define typedef ,您也必须搜索这些。

        7
  •  1
  •   ephemient    16 年前

    Pimpl / d-Pointer 是一种允许您在不破坏兼容性的情况下扩展或重新设计类的更大自由度的策略。

    例如,如果您最初编写

    // foo.h
    class Foo {
    public:
        Foo();
        Foo(const Foo &);
        ~Foo();
        int a() const;
        void a(int);
        int b() const;
        void b(int);
    private:
        class FooPrivate *const d;
    };
    
    // foo.c
    class FooPrivate {
    public:
        FooPrivate() : a(0), b(0) {}
        FooPrivate(const FooPrivate &o) : a(o.a), b(o.b) {}
        int a;
        int b;
    };
    Foo::Foo() : d(new FooPrivate()) {}
    Foo::Foo(const Foo &o) : d(new FooPrivate(*o->d)) {}
    Foo::~Foo() { delete d; }
    int Foo::a() const { return d->a; }
    void Foo::a(int a) { d->a = a; }
    // ...
    

    您可以轻松地将其扩展到

    // foo.h
    class Foo {
    public:
        // ...
        int a() const;
        void a(int);
        int b() const;
        void b(int);
        int c() const;
        void c(int);
        // ...
    };
    
    // foo.c
    class FooPrivate {
        // ...
        int a;
        int b;
        int c;
    };
    // ...
    

    不破坏任何现有的(已编译的!)代码使用 Foo .

        8
  •  0
  •   Mahmoud Al-Qudsi    16 年前

    如果该代码用于通过网络传输数据,则可能会破坏某些功能。

        9
  •  0
  •   Bernd Jendrissek    16 年前

    作为旁白,当我看到typedef FOO。。。结构FUO,就像一个人试图让C代码看起来像C++一样。我意识到我在这里是少数:)

        10
  •  0
  •   HeretoLearn    16 年前

    在C结构的末尾添加新元素总是安全的。事件,如果该结构被传递到不同的进程。重新编译的代码将看到新的结构成员,而未编译的代码将只知道旧的结构大小,并读取其知道的旧成员。 这里的警告是,新成员必须添加到结构的末端而不是在中间。

    推荐文章