Обеспечивает ли использование const global vars вместо enum совместимость с ABI?

В моем проекте библиотеки C у меня есть перечисление, в котором перечислены все возможные типы данных, обрабатываемых библиотекой:

// lib.h
enum types {
    VOID,
    INT,
    FLOAT,
    CONST_INT,
    CONST_FLOAT
}

Код будет скомпилирован в разделяемую библиотеку. В будущих версиях библиотеки мне потребуется вставлять новые записи в перечисление и изменять порядок существующих. Насколько я знаю, это нарушает совместимость с ABI, поскольку перечисление не преобразуется в набор символов, который попадает в библиотеку, а скорее приводит к тому, что любое целое число, которое компилятор присваивает каждой записи, будет жестко запрограммировано. Так ли это?

Если да, то было бы предпочтительнее вместо этого использовать постоянные глобальные переменные, чтобы они появлялись в таблице символов, и, таким образом, я мог бы изменить как порядок, так и значение, присвоенное каждому?

// lib.c
const int VOID = 1;
const int INT = 2;
const int FLOAT = 3;
const int CONST_INT = 4;
const int CONST_FLOAT = 5;

// lib.h
extern const int VOID;
extern const int INT;
extern const int FLOAT;
extern const int CONST_INT;
extern const int CONST_FLOAT;

c abi
person Fabian Schuiki    schedule 12.03.2016    source источник


Ответы (2)


Ты прав. Если вы планируете расширить перечисляемые переменные, это может сделать несовместимыми будущие версии ваших библиотек.
Если вы посмотрите на некоторые из наиболее подходящих программ (например, заголовки MS или Linux), вы увидите, что принятые решения в основном два:

  1. Использование определяет
  2. По-прежнему используйте enum, но присваивайте значение каждой записи

Последнее делает использование перечисления совершенно равным определениям, но сохраняет свойства перечислений.
В вашем случае это может быть:

// lib.h
enum types {
    VOID = 0,
    INT = 1,
    FLOAT = 10,
    CONST_INT = 12,
    CONST_FLOAT = 13
}

Затем, когда в будущем вы добавите другие коды:

// lib.h
enum types {
    VOID = 0,
    INT = 1,
    CUSTOM1 = 3,
    FLOAT = 10,
    CUSTOM2 = 11,
    CONST_INT = 12,
    CONST_FLOAT = 13,
    CUSTOM4 = 20
}

Использование постоянных глобальных переменных может иметь некоторые проблемы, даже если их оптимизировать и заменить константами.

person Frankie_C    schedule 12.03.2016
comment
Помните, что добавление записей в перечисление изменяет тип и может дать больший целочисленный тип для хранения переменных перечисления, поэтому вы иногда видите большие/отрицательные зарезервированные записи заполнения для проверки на будущее. По общему признанию, на практике это в основном проблема с 8-битными ABI, особенно для последовательных перечислений. - person doynax; 13.03.2016
comment
@doynax решение этой проблемы состоит в том, чтобы использовать int в качестве типа любой переменной, которая будет содержать один из этих перечислителей. (Все перечислители int независимо от базового типа перечисления) - person M.M; 13.03.2016
comment
@M.M: Это действительно самый частый обходной путь. Однако немного раздражает отсутствие помощи от отладчика в расшифровке значений. - person doynax; 13.03.2016

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

Изменение перечисления по-прежнему потребует повторной компиляции/связывания и т. д. библиотеки (это не обойти),

Чтобы убедиться, что каждая метка в перечислении имеет конкретное значение, перечисление можно записать примерно так:

enum 
{
    label1 = 0,
    label2 = 1,
    label3 = 20,
    label4 = 5
};

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

person user3629249    schedule 15.03.2016