3

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

关于我可能在哪里搞砸的任何想法?

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

例如(如果我不清楚):

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

现在是:

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

10 回答 10

6

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

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

于 2010-01-21T15:16:33.837 回答
4

如果您使用 sizeof(struct) 在所有位置分配内存并使用 -> 或访问成员。运营商,我不认为你应该面对任何问题。但是,这也取决于您尝试添加成员的位置,如果您不小心,它可能会破坏您的结构对齐。

于 2010-01-21T15:13:48.363 回答
4

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

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

跟进:

由于您尚未发现错误,因此我将停止查看您的结构。有人曾经写过,先找马,再找斑马。也就是说,该错误可能不是外来错误。你的单元测试有多少覆盖率?我假设这是遗留代码,几乎总是意味着 0%,或者至少这是我的经验。这是准确的吗?

于 2010-01-21T15:16:05.823 回答
2

关于我可能在哪里搞砸的任何想法?

没有。一切。这一切都取决于如何、在哪里以及为什么使用它。

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

于 2010-01-21T15:15:26.807 回答
2

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

我假设您不需要在这个巨大的代码库中到处使用新的“c”变量,您只是添加它,以便可以在您正在添加或修改的某些代码中使用它?除了将 c 添加到 foo 之外,您还可以创建一个新结构 bar,其中包含一个 foo 对象和 c。然后在需要的地方使用 bar 。

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

于 2010-01-21T21:03:59.820 回答
1

寻找memcpy, memset, memcmp。这些函数不是按成员的。如果它们使用以前的结构长度,您可能会遇到问题。

还搜索文件以查找struct. 可能有一些函数或方法不使用新的重要字段。正如其他人所说,如果您在#defineor中找到结构typedef,您也必须搜索这些结构。

于 2010-01-21T17:41:44.973 回答
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.

于 2010-01-21T18:59:35.523 回答
0

如果代码用于通过网络传输数据,您可能会破坏一些东西。

于 2010-01-21T15:27:33.730 回答
0

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

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

于 2010-01-21T16:31:05.510 回答
0

Its always safe to add new elements at the end of a C struct. Event if that struct is passed to different processes. The code which has been recompiled will see the new struct member and the code which hasn't been will just be aware of the old struct size and just read the old members its knows about. The caveat here is that new member has to be added at the end of the structure and not in the middle.

于 2010-01-22T03:01:03.760 回答