Скажите, что мне определили структуру где-нибудь глубоко в коде низкого уровня, используемом повсеместно самыми сумасшедшими и неизвестными способами:
struct T {
unsigned short name_len;
char d_name[LENGTH];
}
С сопровождением функций, которые заполняют d_name любыми потребностями, которые будут помещены там, как
struct T* fill( somethingOrOther* X)
И я хотел бы расширить старый struct+function для включения новой переменной:
struct T {
unsigned short name_len;
char d_name[LENGTH];
unsigned short type_len;
char d_type;
}
и новая версия функции также заполнила бы d_type переменную полезными вещами.
Этот тип изменения повредил бы API? Я не мог только использовать новый T вместо старого T и дополнительно получить доступ к новым участникам?
Пока код, использующий этот API, получает объекты T
только как указатели, возвращаемые библиотекой, и не объявляет их сам, malloc
их сам (используя sizeof(struct T)
), или делает что-либо еще, что зависит от размера struct, то все должно быть в порядке. Если вызывающий код обратился к содержимому struct, то вам нужно убедиться, что вы поместили новые члены в конец struct.
Один возможный дополнительный вопрос: зависит ли какой-либо код от того, что d_name
находится в конце структуры, чтобы выделить место для хранения больших имен, если объявленный размер не подходит. Я говорю об этом только потому, что имена членов предполагают, что структура имеет вид dirent
, а это традиционная практика для dirent
.
Если T действительно используется повсюду сумасшедшими и неизвестными способами, то подобное изменение, скорее всего, что-то сломает. Где-нибудь найдется кусок кода, который имеет локальное объявление T вместо того, чтобы использовать ваш заголовочный файл, или приводит 'mystruct *' к 'T *', или что-то столь же отвратительное.
Да - когда вы используете непрозрачный указатель, как этот, то его содержимое не имеет значения. До тех пор, пока ваши пользователи используют только непрозрачные указатели, вы можете возиться со структурой и ее реализацией сколько угодно.
Сумасшествие и неизвестность - это нехорошо. Лучший вариант - просмотреть кодовую базу на наличие struct T и изучить, как она используется, с альтернативным подходом - изменить ее и посмотреть, не сломается ли что-нибудь... Если в коде используются только непрозрачные указатели, вы должны быть на безопасной стороне. Если код обращается к членам, но не делает ничего странного, вы тоже должны быть в безопасности, с полной перекомпиляцией.
Если же он делает что-то странное, как в примере с rettops, то даже совет Юкки может не помочь. Код может использовать жестко закодированное значение sizeof для выполнения арифметики указателей в массиве этих структур...
Возможно, имеет смысл расширить ваши структуры следующим образом:
struct newT {
struct T t;
int newElement;
...
}
Тогда вы сможете безопасно использовать указатель newT в качестве указателя T; стандарт C гарантирует, что перед первым элементом структуры не будет никакой прокладки.