Каков пример неправильного использования контейнера ARM C Compiler Option Enum всегда int?

В http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0065d/Cihejcda.html есть вариант и примечание:

Контейнер перечисления всегда целочисленный

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

Примечание
Этот параметр не рекомендуется для общего использования и не требуется для ANSI-совместимого источника. При неправильном использовании эта опция может привести к ошибкам в результирующем изображении.

Каков пример такого неправильного использования в C?


Фон:

Я разрабатываю встроенное приложение на C, удаление этого флага компилятора исправило ошибку (или только симптомы другой ошибки). Ошибка была

sprintf(big_enought_char_array, "%4.1f", float_var)

вызов функции неправильно форматировал числа с плавающей запятой.

Это было почти исправлено с помощью правильного выравнивания памяти, используемой в качестве стека. Почти исправлено, потому что содержимое массива было в порядке, но десятичная точка имела неправильный символ. Удаление упомянутой выше опции компилятора устранило проблему. Итак, вопрос в том, что эта опция компилятора делает точно и что является неправильным ее использованием?


person memic    schedule 27.10.2015    source источник
comment
Вопросы, требующие помощи в отладке (почему этот код не работает?), должны включать желаемое поведение, конкретную проблему или ошибку и кратчайший код, необходимый для их воспроизведения, в самом вопросе. Вопросы без четкой формулировки проблемы бесполезны для других читателей. См. Как создать минимально воспроизводимый пример.   -  person too honest for this site    schedule 27.10.2015
comment
Поплавки не связаны с перечислениями. Так что, похоже, здесь задействован еще один эффект.   -  person too honest for this site    schedule 27.10.2015


Ответы (3)


Я предполагаю, что вы имеете в виду этот вариант:

Контейнер перечисления всегда целочисленный

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

В C тип, используемый для перечисляемого типа, определяется реализацией (но константа enum всегда равна int): это целочисленный тип, который может представлять все enum константы.

Если вы установите тип перечисляемого типа на int, я могу подумать о двух проблемах:

1) если вы заставите свою программу полагаться на тот факт, что enum являются int (например, предполагая, что sizeof совпадает с sizeof (int)), она не будет переносима на другие системы.

2) если вы определяете константу со значением, превышающим INT_MAX (или которое не может представлять int), скажем, например, UINT_MAX, ваш тип не сможет представить ее там, где C enum гарантированно ее представляет.

Что касается вашей конкретной проблемы с вызовом sprintf, она кажется совершенно не связанной с этой опцией. Вы, вероятно, вызываете какое-то неопределенное поведение перед своим вызовом.

person ouah    schedule 27.10.2015

что именно делает этот параметр компилятора

Ну, обычно ваш средний enum не имеет, например. 2³² записи - в большинстве случаев у него даже нет 256. В этом случае компилятор C обычно может использовать более короткое представление значения, например. один байт.

Использование этого флага заставит все enum занимать одну и ту же память размером int (читай: длина слова). Это только в паре довольно особых случаев, и, очевидно, это ломает sprintf; Я не думаю, что это обычное дело, так что: какую libc реализацию вы используете? Убедитесь, что он явно не запрещает использование этого флага, и при необходимости отправьте отчет об ошибке. Сделайте минимальный тестовый пример, чтобы продемонстрировать проблему.

person Marcus Müller    schedule 27.10.2015
comment
Почему это очевидно ломает sprintf? - person Breaking not so bad; 27.10.2015
comment
@ringø: Маркус имеет в виду очевидно, как можно заметить, а не само собой разумеющееся. - person Jongware; 27.10.2015
comment
или не использовать sprintf все вместе :) - person Tomer W; 27.10.2015
comment
я использую встроенные версии sprintf(), поставляемые с компилятором armcc от keil. Я попробовал минимальный тестовый пример, но пока не могу воспроизвести его без запуска встроенной ОС реального времени. поэтому предположим, что что-то уничтожило мою таблицу поиска, используемую в функции sprintf, если она используется в реализации. - person memic; 27.10.2015
comment
@TomerW Он тоже этого не делает, поэтому ему интересно, почему поведение меняется, когда установлен флаг компилятора (я предполагаю) - person Russ Schultz; 27.10.2015
comment
@Расс Шульц: точно - person memic; 27.10.2015

Вот мое предположение относительно sprintf():

Ваш стек был фактически объявлен как массив char[], и он был среди некоторых enum переменных или находился в структуре __packed. Изменение enum с char на int (или наоборот) изменило выравнивание переменных стека, выровняв поплавок. (третья переменная sprintf(), являющаяся float, почти наверняка будет передана в стек)

ARM требует, чтобы стек был выровнен по 8 байтам. Лучше объявить его как uint64_t (и определенно не в структуре __packed), чтобы его выравнивание всегда было правильным.

person Russ Schultz    schedule 27.10.2015