Если перечисление никогда не будет использоваться в API?

Я использую библиотеку C, предоставленную мне уже скомпилированной. У меня есть ограниченная информация о компиляторе, версии, параметрах и т.д., Используемых при компиляции библиотеки. Интерфейс библиотеки использует enum как в структурах, которые передаются, так и непосредственно в качестве переданных параметров.

Вопрос: как я могу заверить или установить, что когда я компилирую код для использования предоставленной библиотеки, мой компилятор будет использовать тот же размер для этих enum s? Если это не так, структуры не выстраиваются в линию, и передача параметров может быть испорчена, например. long против int.

Моя забота проистекает из стандарта C99, в котором говорится, что тип enum:

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

Насколько я могу судить, до тех пор, пока самое большое значение подходит, компилятор может выбрать любой тип, который он чертит хорошо радует, эффективно по прихоти, потенциально изменяющийся не только между компиляторами, но и разными версиями одного и того же компилятора и/или компилятора. Он мог выбирать 1, 2, 4 или 8-байтовые представления, что приводило к потенциальной несовместимости в обеих структурах и передаче параметров. (Он также может выбирать подписанный или неподписанный, но я не вижу механизма для этого в этом контексте.)

Я что-то упустил? Если я чего-то не пропущу, значит ли это, что enum никогда не должно использоваться в API?

Update:

Да, я что-то упустил. Хотя спецификация языка здесь не помогает, как отмечает @Barmar, используется двоичный интерфейс приложения (ABI). Или, если это не так, тогда ABI является недостаточным. ABI для моей системы действительно указывает, что enum должен быть подписанным четырехбайтовым целым числом. Если компилятор не подчиняется этому, то это ошибка. Учитывая полный ABI и совместимые компиляторы, enum можно безопасно использовать в API.

Ответ 1

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

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

Кроме того, все компиляторы для конкретной ОС должны быть совместимы с OS ABI. В противном случае у вас будет гораздо больше проблем, например, библиотека, использующая 64-разрядный int, в то время как вызывающий использует 32-разрядный int. В идеале, ABI должен ограничивать представление enum s, чтобы обеспечить совместимость.

В более общем плане спецификация языка гарантирует совместимость программ, скомпилированных с той же реализацией. ABI обеспечивает совместимость между программами, скомпилированными с различными реализациями.

Ответ 2

Из вопроса:

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

Я удивлен этим. Я подозреваю, что на самом деле вы компилятор выберете для вашего перечисления 64-разрядный (8-байтовый) размер, если вы определите перечислимую константу со значением больше 2 ^ 32.

На моих платформах (MinGW gcc 4.6.2 таргетинг на x86 и gcc 4,.4 на таргетинг на Linux x86_64) следующий код говорит, что я получаю как 4, так и 8 байтовые перечисления:

#include <stdio.h>

enum { a } foo;
enum { b = 0x123456789 } bar;

int main(void) {
    printf("%lu\n", sizeof(foo));
    printf("%lu", sizeof(bar));   
    return 0;
}

Я скомпилирован с помощью переключателей -Wall -std=c99.

Я думаю, вы могли бы сказать, что это ошибка компилятора. Но альтернативы удаления поддержки перечислимых констант больше 2 ^ 32 или всегда с использованием 8-байтовых перечислений кажутся нежелательными.

Учитывая, что эти общие версии GCC не предоставляют перечисление фиксированного размера, я думаю, что единственным безопасным действием вообще является не использование перечислений в API.

Дальнейшие примечания для GCC

Компиляция с помощью "-pedantic" вызывает следующие предупреждения:

main.c:4:8: warning: integer constant is too large for 'long' type [-Wlong-long]
main.c:4:12: warning: ISO C restricts enumerator values to range of 'int' [-pedantic]

Поведение можно настроить с помощью переключателей --short-enums и -no-short-enums.

Результаты с Visual Studio

Компиляция вышеуказанного кода с VS 2008 x86 вызывает следующие предупреждения:

warning C4341: 'b' : signed value is out of range for enum constant
warning C4309: 'initializing' : truncation of constant value

И с VS 2013 x86 и x64, просто:

warning C4309: 'initializing' : truncation of constant value