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

时间:2010-01-21 15:08:41

标签: c++ c struct codebase

所以我正在使用这个巨大的代码库,并意识到其中一个结构缺少一个重要的领域。我尽可能密切地查看代码(使用结构)并得出结论,添加一个额外的字段不会破坏它。

关于我可以搞砸的任何想法?

另外:欢迎设计建议 - 我能做到这一点的最佳方法是什么?

例如(如果我不清楚):

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

现在是:

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

10 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:4)

如果您使用sizeof(struct)在所有地方分配内存并使用 - >访问成员要么 。经营者,我认为你不应该遇到任何问题。但是,它还取决于您尝试添加成员的位置,如果您不小心,它可能会搞砸您的结构对齐。

答案 2 :(得分:4)

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

  1. 每当您更改代码并重新编译时,您都会引入查找“隐藏”错误的功能。也就是说,未初始化的指针,你的新数据结构可能足以被破坏。
  2. 您确定在使用之前初始化c吗?
  3. 跟进:

    由于你还没有找到错误,我会停止查看你的结构。有人曾经写过先寻找马,斑马第二。也就是说,错误可能不是一个奇特的错误。您在单元测试中的覆盖范围是多少?我假设这是遗留代码,几乎总是意味着0%或至少这是我的经验。这准确吗?

答案 3 :(得分:2)

  

关于我可以搞砸的任何想法?

无。一切。这一切都取决于使用方式,地点和原因。

假设你所说的这个结构是一个C风格的POD而且代码是最简单的,你就可以逃脱它。但是,当您尝试更具野心的事情时,您正在处理对齐问题(取决于您创建对象的方式和位置)以及至少填充。如果这是C ++并且您的POD包含自定义运算符/ ctors等 - 您将遇到很多麻烦。如果您依赖有关的字节序等,可能会出现跨平台问题。

答案 4 :(得分:1)

寻找memcpy, memset, memcmp。这些功能不是成员。如果使用之前的结构长度使用它们,则可能会出现问题。

还搜索文件以查找struct的每个实例。可能存在不使用新重要字段的功能或方法。正如其他人所说,如果你在#definetypedef中找到结构,你也必须搜索它们。

答案 5 :(得分:1)

因为您标记了问题C ++:

对于未来,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而不破坏任何现有(已编译!)代码。

答案 6 :(得分:1)

如果代码有一套强大的单元测试,那么跟踪问题可能要容易得多(你要求设计建议;)

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

至于实际的错误,它可能是任何信息都很少的东西,但如果我不得不猜测,我会说有人在某处使用了魔法数字而不是sizeof()。

答案 7 :(得分:0)

如果代码用于通过网络传输数据,则可能会破坏事物。

答案 8 :(得分:0)

如果在第一个成员之外的任何地方添加结构成员会破坏任何内容,那么代码具有未定义的行为,这是错误的。所以至少你有其他人(或你的早期自己)应该为破损负责。但是,未定义的行为包括“碰巧做我们想做的事情”,正如其他人所说的那样,注意内存分配,序列化(网络和文件IO)。

顺便说一下,当我看到typedef FOO ... struct FOO时,我总是畏缩,好像有人试图使C代码看起来像C ++。我意识到我在这里属于少数人:)

答案 9 :(得分:0)

在C结构的末尾添加新元素总是安全的。将该结构传递给不同进程的事件。已经重新编译的代码将看到新的struct成员和尚未知道的代码将只知道旧的struct大小并且只读取它所知道的旧成员。 需要注意的是,新成员必须添加到结构的末尾而不是中间。