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

发布于 2024-08-18 20:36:08 字数 375 浏览 9 评论 0原文

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

关于我可能搞砸的地方有什么想法吗?

另外:欢迎提供设计建议 - 我实现这一目标的最佳方法是什么?

例如(如果我没说清楚的话):

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

现在是:

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

So I'm working with this huge repository of code and have realized that one of the structs lack an important field. I looked at the code (which uses the struct) as closely as I could and concluded that adding an extra field isn't going to break it.

Any ideas on where I could've screwed up?

Also: design advice is welcome - what's the best way I can accomplish this?

E.g. (if I wasn't clear):

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

Now it's :

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

倒带 2024-08-25 20:36:08

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

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

If that structure is being serialized/deserialized anywhere, be sure to pay attention to that section of the code.

Double check areas of the code where memory is being allocated.

歌入人心 2024-08-25 20:36:08

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

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

跟进:

既然您还没有发现错误,我将停止查看您的结构。有人曾经写道,先寻找马,其次寻找斑马。也就是说,该错误可能不是一个外来错误。您的单元测试覆盖率有多少?我假设这是遗留代码,几乎总是意味着 0% 或者至少这是我的经验。这准确吗?

From what you've written above I can't see anything wrong. Two things I can think of:

  1. Whenever you change code and recompile you introduce the ability to find "hidden" bugs. That is, uninitialized pointers which your new data structure could be just big enough to be corrupted.
  2. Are you making sure you initialize c before it gets used?

Follow Up:

Since you haven't found the error yet I'd stop looking at your struct. Someone once wrote look for horses first, zebras second. That is, the error is probably not an exotic one. How much coverage do you have in your unit tests? I'm assuming this is legacy code which almost invariably means 0% or at least that's been my experience. Is this accurate?

雅心素梦 2024-08-25 20:36:08

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

If you are using sizeof(struct) to allocate memory at all places and are accessing the members using -> or . operators, I don't think you should face any problem. But, it also depends on where you are trying to add the member, it might screw up your structure alignment if you are not careful.

深空失忆 2024-08-25 20:36:08

关于我可能搞砸的地方有什么想法吗?

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

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

Any ideas on where I could've screwed up?

Nothing. Everything. It all depends on how, where and why this is used.

Assuming this structure you talk about is a C-style POD and the code is but the simplest, you'll get away with it. But, the moment you are trying something more ambitious, you are dealing with alignment issues (depending on how and where you create objects) and padding at least. If this is C++ and your POD contains custom operators/ctors etc -- you're getting into a lot of trouble. Cross-platform issues may arise, if you rely on the endianness ever etc.

花开浅夏 2024-08-25 20:36:08

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

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

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

If the code had a robust set of unit tests, it would probably be much easier to track down the problem (you asked for design advice ;) )

I assume you don't need to use the new 'c' variable everywhere in this giant codebase, you're just adding it so you can use it in some code you're adding or modifying? Instead of adding c to foo, you could make a new struct, bar, which contains a foo object and c. Then use bar where it's needed.

As for the actual bug, it could be anything with so little information to go on, but if I had to guess, I'd say someone used a magic number instead of sizeof() somewhere.

但可醉心 2024-08-25 20:36:08

查找memcpy、memset、memcmp。这些功能不是按成员划分的。如果使用以前的结构长度,您可能会遇到问题。

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

Look for memcpy, memset, memcmp. These functions are not member-wise. If they were used using the previous structure length, you may have problems.

Also search the files for every instance of the struct. There may be functions or methods that do not use the new important field. As others have said, if you find the structure in a #define or typedef, you'll have to search those too.

薄荷梦 2024-08-25 20:36:08

既然您标记了您的问题 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 轻松扩展它

// 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;
};
// ...

,而不会破坏任何现有(已编译!)代码。

Since you tagged your question C++:

For the future, Pimpl/d-Pointer is a strategy that allows you much greater freedom in extending or re-designing your classes without breaking compatibility.

For example, if you had originally written

// 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; }
// ...

you can easily extend this to

// 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;
};
// ...

without breaking any existing (compiled!) code using Foo.

鱼窥荷 2024-08-25 20:36:08

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

If the code is used to transfer data across the network, you could be breaking things.

剩一世无双 2024-08-25 20:36:08

如果在第一个成员以外的任何地方添加结构成员会破坏任何内容,则代码具有未定义的行为,并且是错误的。因此,至少你可以将损坏归咎于其他人(或你以前的自己)。但是,是的,未定义的行为包括“恰好做了我们希望它做的事情”,所以正如其他人所说,请注意内存分配、序列化(网络和文件 IO)。

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

If adding a structure member anywhere other than as the first member breaks anything, then the code has undefined behaviour and it's wrong. So at least you have someone else (or your earlier self) to blame for the breakage. But yes, undefined behaviour includes "happens to do what we'd like it to do", so as the other guys say, watch out for memory allocation, serialization (network and file IO).

As an aside, I always cringe when I see typedef FOO ... struct FOO, as if one is trying to make C code look like C++. I realize I'm in a minority here :)

木槿暧夏七纪年 2024-08-25 20:36:08

在 C 结构体末尾添加新元素始终是安全的。如果该结构传递到不同的进程,则发生事件。已重新编译的代码将看到新的结构成员,而未重新编译的代码将仅了解旧的结构大小并仅读取其所了解的旧成员。
这里需要注意的是,必须在结构的末尾添加新成员,而不是在中间。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文