Используя в качестве примера avr-gcc, типы int указываются шириной 16 бит. Выполнение операций над 8-битными операндами в C приводит к тому, что эти операнды преобразуются в 16-битные типы int из-за целочисленного продвижения в C. Означает ли это, что все 8-битные арифметические операции в AVR будут намного дольше, если они записаны в C, чем если написано на ассемблере из-за целочисленного продвижения C?
microcontroller
avr
c
pr871
источник
источник
Ответы:
Короче:
Целочисленное повышение до 16 битов всегда имеет место - стандарт C обеспечивает это. Но компилятору разрешено оптимизировать вычисления до 8 бит (компиляторы встроенных систем обычно довольно хороши в такой оптимизации), если он может сделать вывод, что знак будет таким же, как если бы тип был повышен.
Это не всегда так! Неявные изменения подписи, вызванные целочисленным продвижением, являются распространенным источником ошибок во встроенных системах.
Подробное объяснение можно найти здесь: Правила продвижения неявных типов .
источник
как и ожидалось, fun1 - это целые числа, так же как и 16-битная математика.
Хотя это технически неверно, так как это 16-битное дополнение, вызываемое кодом, даже неоптимизированный этот компилятор удалил adc из-за размера результата.
не очень удивился, что здесь происходит продвижение, компиляторы раньше не делали этого, не зная, с какой версией это начало происходить, столкнулся с этим в начале моей карьеры и, несмотря на то, что компиляторы продвигались не по порядку (как выше), делал продвижение, хотя я сказал это делать учар математику, не удивился.
и идеал, я знаю, что это 8-битный, хочу 8-битный результат, поэтому я просто сказал, чтобы он делал 8-битный полностью.
Так что в общем случае лучше стремиться к размеру регистра, который в идеале равен размеру (u) int, для 8-битного mcu, подобного этому, авторам компилятора приходилось идти на компромисс ... Дело в том, что привычка использование uchar для математики, которое, как вы знаете, не требует более 8 бит, так как когда вы перемещаете этот код или пишете новый код на процессоре с большими регистрами, теперь компилятор должен начать маскировать и подписывать расширение, что некоторые делают изначально в некоторых инструкциях, а другие нет.
форсирование 8 бит стоит дороже. Я немного обманул / много, мне нужно немного более сложные примеры, чтобы увидеть больше этого на справедливой основе.
РЕДАКТИРОВАТЬ на основе обсуждения комментариев
не удивительно. Хотя почему оптимизатор оставил эту дополнительную инструкцию, нельзя ли использовать ldi на r19? (Я знал ответ, когда спросил).
EDIT2
для авр
чтобы избежать вредной привычки или нет 8-битное сравнение
очевидно, что оптимизация была включена всего за секунду, чтобы попробовать с вашим собственным компилятором, чтобы увидеть, как он сравнивается с моим выводом, но в любом случае:
И да, использование байтов для переменных байтового размера, безусловно, на avr, pic и т. Д., Сэкономит вашу память, и вы действительно захотите сохранить ее ... если вы на самом деле ее используете, но, как показано здесь, как можно меньше будет в памяти, как можно больше в регистрах, поэтому экономия флэш-памяти достигается за счет отсутствия дополнительных переменных, а оперативная экономия может быть или не быть реальной ..
источник
unsigned char
поэтому он должен выполнить переход до 16 бит, как требуется по стандарту.(a<<8)|b
всегда неверен для любой системы, гдеint
16 бит.a
будет неявно повышен доint
которого подписан. В случае,a
если в MSB хранится значение, вы в конечном итоге сдвигаете эти данные в знаковый бит 16-битного числа, что вызывает неопределенное поведение.Не обязательно, поскольку современные компиляторы хорошо справляются с оптимизацией сгенерированного кода. Например, если вы напишите,
z = x + y;
где находятся все переменныеunsigned char
, компилятор должен их преобразоватьunsigned int
перед выполнением вычислений. Однако, поскольку конечный результат будет без изменений, компилятор сгенерирует код, который просто добавляет 8-битные переменные.Конечно, это не всегда так, например, результат
z = (x + y)/2;
будет зависеть от старшего байта, поэтому продвижение будет происходить. Этого все еще можно избежать, не прибегая к сборке, возвращая промежуточный результат кunsigned char
.Некоторых из таких недостатков можно избежать, используя параметры компилятора. Например, многие 8-битные компиляторы имеют прагму или параметр командной строки для размещения типов перечисления в 1 байт, а не
int
как того требует C.источник
int
, посколькуchar
он, скорее всего, не будет иметь такой же рейтинг конверсии, какint
на любой платформе.int
(да, это противоречиво). С11 6.7.2.2Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined...