Извините, замену while (--n) {...} на while (n-=1) {...}
И все ваши перечисляемые преимущества рассеиваются как дым.
Хм, действительно, чего-то я стормозил (думал в терминах паскаля где все такие трюки недопустимы). Спасибо.
В таких ситуациях делают расширения языка (убивающие переносимость, но на неё и не замахиваются...).
Ваши б слова да разработчикам компиляторов в уши ... Эх. Не делают, паразиты. А оптимизаторы не доросли до замены переносимого кода на аппаратно поддерживаемый целевой платформой (тому примеров море, хотя бы для AVR, вроде распространённая архитектура, а компиляторы между ужасны и лишь плохи).
К тому же, если вы знаете, какие три команды хотите получить, почему бы их и не написать, хотя бы в ассемблерной вставке.
Причин несколько: проблемы с указанием точки перехода (придётся вместо стандартного for() использовать метку и jump, что возможно, но криво), проблемы с получением переменной в регистр (не всегда известен адрес переменной или есть способы его получить), проблемы с указанием компилятору что этот регистр оказывается занят и только в рамках этого куска кода, проблемы с размещением переменной (неясно заранее будет ли она в памяти или регистре, если насильно не положить её в память, что плохо), хотелось бы всё же переносимости исходного кода (потому и мучался с С), остальной код не сильно лучше и поблажка тут предрасположит к переписыванию на асм всей функции (что не есть плохо, но хотелось избежать). Ну, что вспомнил.
После дня борьбы с компилятором остановился на самом приемлимом для меня коде (и С и машинном). И после каждой компиляции приходится смотреть не передумал ли вдруг компилятор и не испортил ли опять этот кусок (ибо были примеры такого поведения).
(Про другие языки и глюки компиляторов)
Для вашей ситуации хорошо бы подошли аналоги B/BCPL/C--, неужели их нет?
Не знаю. Даже больше скажу, не уверен что есть другие компиляторы С кроме IAR и Keil (Cosmic это кошмар), в данном случае это было семейство STM8. Про другие языки вообще глухо, может и есть, но качество компилятора под большим вопросом. Даже в этих компиляторах (конкретно IAR) встречаются совершенно невообразимые глюки, например год назад был возврат партии изделий из-за ошибочного функционирования, после долгих разбирательств, благо глюк воспроизводился 100%, оказалось компилятор самовольно назначил две разные переменные на один адрес в eeprom, без всяких предупреждений или уведомлений! Узнал лишь после анализа машинного кода в hex файле! Это вообще как называется?!
Обе переменные были корректно объявлены и обе использовались, с чего вдруг ему что-то померещилось не представляю. Оказалось эта ситуация, с конкретно этими переменными, и конкретными значениями в них, тестами не покрывалась, хотя по отдельности они проверялись и работали правильно. Хотел отослать код в техподдержку компилятора, но любая модификация кода (с целью упрощения) случайным образом исправляла результат компиляции. Промучавшись ещё пару дней в попытках получить минимальный глючный пример бросил это занятие и плюнул, лишь проверяю машинный код в hex файле (в никаких других файлах глюка не видно!! даже в lst и map!) перед передачей на производство. Понимаете глубину жопы? Нигде глюка не видно кроме бинарной прошивки! Хорошо я разбираюсь в ассемблере и могу понять что означают байты в прошивке, а если нет, как проверять правильность машинного кода? Это риторические вопросы, вопль души, отвечать не нужно.
Предложение заменить МК на более распространённый не проходит, STM8 стоил 20р, ближайший аналог (AVR tiny) стоил около 100р, это существенно.
Переписать всё на асм для уверенности в корректности кода отбрасывается: лень, минус переносимость (она не требовалась 100%, но было желание позже МК сменить), затраты времени, сложность поддержки. Переписать на асме только работу с этими переменными тоже не имеет смысла, она размазана по 10% кода и проблемы полезут лавинообразно (уже ходил по этим граблям).
В общем, как уже говорил выше, для mainstream архитектур всё более-менее неплохо (или даже хорошо), но чуть шаг в сторону (от x86, ARM, AVR, PIC, i51) — и сразу море проблем, для некоторых рассматриваемых мною МК существует ровно один неудобный и глючный компилятор С от производителя МК
и всё, без вариантов, даже асма нет.
Ещё я полгода-год назад видел великолепное решение, но в другую сторону: exitwhen, решающее заодно и выход из нескольких вложенных циклов
Да, это похоже красивое и удобное решение
одной из проблем. Но как оно реализуемо в уже используемых компиляторах я не знаю. Плюс другие проблемы оно не решает (например модификацию счётчика цикла внутри самого цикла, некоторые языки это запрещают, даже пределы не дают менять внутри цикла).
Ну почему же? x += n можно определить всегда как n-кратный инкремент.
Можно. Возможно поимев проблемы с обработкой исключительных ситуаций (выход за пределы объекта), скоростью, плохой детерминированостью результата (вместо двух исходов возможны n+1 исходы), сложностью контроля переполнения выходных буферов (при инкременте переполнение буфера контролируется на каждой итерации, при n-кратном лишь после добавления в буфер n значений, а они могут быть разной длины и оценить заранее не всегда возможно). Можно, но часто ценой неадекватного увеличения кода.
Но, по-моему, без трюков лучше.
Наверное тут уже вопрос вкусов. Аргументы есть и за и против. Но с плохим оптимизатором (а он часто
очень плох) лучше писать ровно то, что хочешь получить на выходе.