2010-01-21 2 views
3

Итак, я работаю с этим огромным хранилищем кода и понял, что одной из структур не хватает важного поля. Я посмотрел на код (который использует структуру) настолько близко, насколько я мог, и пришел к выводу, что добавление дополнительного поля не нарушит его.Добавление поля в структуру без нарушения существующего кода

Любые идеи о том, где я мог бы прищуриться?

Также: Консультация по дизайну приветствуется - как я могу это сделать?

E.g. (если я не ясно):

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

Теперь:

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

Добавить настоящий код. Возможно, вы что-то пропустили. – wheaties

+0

Как я уже сказал, это ** огромный ** репозиторий кода, который я не могу опубликовать. Все, о чем я прошу, это советы по дизайну и то, что я мог пропустить. – Jacob

+0

Как используется структура? У вас есть границы байтов? – 2010-01-21 15:15:22

ответ

4

Из того, что вы написали выше, я не вижу ничего плохого. Две вещи, которые я могу придумать:

  1. Всякий раз, когда вы меняете код и перекомпилируете, вы вводите возможность поиска «скрытых» ошибок. То есть, неинициализированные указатели, что ваша новая структура данных может быть достаточно большой, чтобы быть поврежденной.
  2. Вы убедитесь, что инициализировали c, прежде чем он будет использоваться?

Follow Up:

Поскольку вы не нашли ошибку пока я налюбоваться на свою структуру. Кто-то однажды написал для лошадей сначала, а зебры - второй. То есть ошибка, вероятно, не является экзотической. Сколько у вас очков в ваших модульных тестах? Я предполагаю, что это устаревший код, который почти всегда означает 0% или, по крайней мере, это мой опыт. Это точно?

+0

Lol, был момент, когда он был инициализирован, я забыл, что это, скорее всего, будет принято :) – Jacob

+0

По-прежнему пытается разобраться? – wheaties

+0

Ну, на самом деле - я не могу найти никаких других проблем, поэтому ... – Jacob

4

Если вы используете SizeOf (STRUCT) для выделения памяти во всех местах и ​​доступ к членам с помощью -> или , операторов, я не думаю, что вам стоит столкнуться с какой-либо проблемой. Но это также зависит от того, где вы пытаетесь добавить участника, это может испортить выравнивание вашей структуры, если вы не будете осторожны.

+0

Выравнивание структуры, спасибо! Я ищу что-то в этом направлении. – Jacob

2

Любые идеи о том, где я мог бы прищуриться?

Ничего. Все. Все зависит от того, как, где и почему это используется.

Предполагая, что эта структура, о которой вы говорите, является P-образным POD, а код является самым простым, вам это не удастся. Но, как только вы пытаетесь сделать что-то более амбициозное, вы имеете дело с проблемами выравнивания (в зависимости от того, как и где вы создаете объекты) и, по крайней мере, отступом. Если это C++, и ваш POD содержит пользовательские операторы/ctors и т. Д., Вы получаете много проблем. Кросс-платформенные вопросы могут возникать, если вы полагаетесь на достоверность когда-либо и т. Д.

6

Если эта структура сериализуется/десериализируется в любом месте, обязательно обратите внимание на этот раздел кода.

Двойные области проверки кода, в котором выделяется память.

+0

Это отличная идея - к счастью, без сериализации на данный момент. – Jacob

0

Если код используется для передачи данных по сети, вы можете нарушить работу.

0

Если добавить элемент структуры в любом месте, кроме как первый элемент, что-то сломает, то код имеет неопределенное поведение, и это неправильно. Так что, по крайней мере, у вас есть кто-то другой (или ваш прежний я), который виноват в поломке. Но да, неопределенное поведение включает в себя «происходит то, что мы хотели бы сделать», так как другие ребята говорят, следите за распределением памяти, сериализацией (сетевым и файловым IO).

Как в стороне, я всегда сжимаю, когда вижу typedef FOO ... struct FOO, как если бы кто-то пытался сделать код C похожим на C++. Я понимаю, что я в меньшинстве здесь :)

+0

И это одинаково бессмысленно для 'typedef struct FOO ... FOO' в C++, где' struct FOO' уже делает 'FOO' доступным без префикса' struct'. – ephemient

1

Ищите memcpy, memset, memcmp. Эти функции не являются членами. Если они использовались с использованием предыдущей длины структуры, у вас могут быть проблемы.

Также ищите файлы для каждого экземпляра struct. Могут быть функции или методы, которые не используют новое важное поле. Как говорили другие, если вы найдете структуру в #define или typedef, вам также придется искать их.

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.

1

Если код был надежный набор модульных тестов, вероятно, было бы намного легче отследить проблему (вы просили дизайн советы;))

Я предполагаю, что вы не должны использовать новый переменная 'c' везде в этой гигантской кодовой базе, вы просто добавляете ее, чтобы использовать ее в каком-то коде, который вы добавляете или изменяете? Вместо добавления c в foo вы можете создать новую структуру, панель, содержащую объект foo и c. Затем используйте панель, где это необходимо.

Что касается фактической ошибки, то это может быть что угодно, с такой небольшой информацией, но если я должен был догадаться, я бы сказал, что кто-то использовал магическое число вместо sizeof().

0

Его всегда безопасно добавлять новые элементы в конце структуры C. Событие, если эта структура передается различным процессам. Код, который был перекомпилирован, увидит новый член структуры, а код, который не был, просто будет знать о размере старой структуры и просто прочитать старые члены, о которых он знает. Предостережение здесь заключается в том, что новый член должен быть добавлен в конце структуры, а не посередине.