alx2 0 26 ноября, 2008 Опубликовано 26 ноября, 2008 (изменено) · Жалоба Сейчас у меня вот такие опции:Хм. Странно. Ничего подозрительного не вижу, и на простых примерах воспроизвести не могу. Не генерится у меня код для таких функций... Да ну? Где Вы это вычитали? Сдвиг в Си для знаковых операндов всю жизнь был арифметический, с учетом знака.Читаем первоисточник: The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2^E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined. When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded. 87) ..... 87) This is often called ``truncation toward zero''. Обрати внимание, что результат оператора / - не есть целая часть арифметического частного. И в качестве упражнения тестовый пример: alx2% cat test.c #include <stdio.h> int main(void) { int x = -5; return printf("%d, %d\n", x / 2, x >> 1); } alx2% gcc -O2 -o t test.c alx2% ./t -2, -3 А вот то, что гнусь не поставил команду ASR, а позвал деление - это непонятно.Попробуй привести код со сдвигами, выполняющий деление значения типа int (уже находящегося в регистрах) на 2, который был бы не длиннее трех машинных инструкций (напоминаю, что sonycman просил оптимизировать по размеру кода). Изменено 26 ноября, 2008 пользователем alx2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 26 ноября, 2008 Опубликовано 26 ноября, 2008 · Жалоба -2, -3 Однако, сдвиг действительно арифметический. Более подробно посмотрю этот момент, когда попаду за комп, потому как с трубы лень искать. Возможно, я и не прав. Попробуй привести код со сдвигами, выполняющий деление значения типа int (уже находящегося в регистрах) на 2, который был бы не длиннее трех машинных инструкций (напоминаю, что sonycman просил оптимизировать по размеру кода). Если уж быть точным, там тип signed char у sonycman, так что inc rx, asr rx вполне бы прошло. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alx2 0 26 ноября, 2008 Опубликовано 26 ноября, 2008 · Жалоба Если уж быть точным, там тип signed char у sonycman, так что inc rx, asr rx вполне бы прошло.Если быть совсем точным, :) во-первых, sonycman, к сожалению, не привел деклараций переменных. Во-вторых, там на два делилась разность двух целых значений, которая уже в один байт не помещается. В-третьих, даже если бы не было разности, простого inc rx, asr rx недостаточно: оно дает неверные значения для нечетных положительных чисел. Например, 1/2 даст 1, тогда как должно быть 0. Как минимум, требуется еще sbrs rx,7 в начале, что дает все те же три инструкции... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 26 ноября, 2008 Опубликовано 26 ноября, 2008 · Жалоба оно дает неверные значения для нечетных положительных чисел. Например, 1/2 даст 1, тогда как должно быть 0. Как минимум, требуется еще sbrs rx,7 в начале, что дает все те же три инструкции... Да. Согласен. Чтото я погорячился. Правда про signed char упомянуто. На предыдущей странице. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 26 ноября, 2008 Опубликовано 26 ноября, 2008 · Жалоба Однако, сдвиг действительно арифметический. Более подробно посмотрю этот момент, когда попаду за комп, потому как с трубы лень искать. Возможно, я и не прав. Если уж быть точным, там тип signed char у sonycman, так что inc rx, asr rx вполне бы прошло. Да, там у меня char: #define LCD_WIDTH 96 byte lcdGetStringWidth(PGM_P text); void lcdPrintText(PGM_P text, byte flags, signed char x, signed char y) switch(flags & 0xe0) { case TXT_CENTERED: if (x < 0) { x = (LCD_WIDTH + x - lcdGetStringWidth(text)) / 2; } ... Но смысла в нём мало - всё равно всё тупо "растягивается" до 16-ти бит :crying: ... даже switch: { switch(flags & 0xe0) e3a: 70 e0 ldi r23, 0x00; 0 e3c: 60 7e andi r22, 0xE0; 224 e3e: 70 70 andi r23, 0x00; 0 e40: 60 38 cpi r22, 0x80; 128 e42: 71 05 cpc r23, r1 e44: 21 f0 breq .+8 ; 0xe4e <lcdPrintText(char const*, unsigned char, signed char, signed char)+0x26> e46: 60 3c cpi r22, 0xC0; 192 e48: 71 05 cpc r23, r1 e4a: 11 f5 brne .+68 ; 0xe90 <lcdPrintText(char const*, unsigned char, signed char, signed char)+0x68> e4c: 1d c0 rjmp .+58 ; 0xe88 <lcdPrintText(char const*, unsigned char, signed char, signed char)+0x60> e4e: c4 2f mov r28, r20 e50: dd 27 eor r29, r29 e52: c7 fd sbrc r28, 7 e54: d0 95 com r29 { case TXT_CENTERED: if (x < 0) e56: 47 ff sbrs r20, 7 e58: 0c c0 rjmp .+24 ; 0xe72 <lcdPrintText(char const*, unsigned char, signed char, signed char)+0x4a> { x = (LCD_WIDTH + x - lcdGetStringWidth(text)) / 2; e5a: da df rcall .-76 ; 0xe10 <lcdGetStringWidth(char const*)> e5c: c0 5a subi r28, 0xA0; 160 e5e: df 4f sbci r29, 0xFF; 255 e60: 9e 01 movw r18, r28 e62: 28 1b sub r18, r24 e64: 31 09 sbc r19, r1 e66: c9 01 movw r24, r18 e68: 62 e0 ldi r22, 0x02; 2 e6a: 70 e0 ldi r23, 0x00; 0 e6c: 17 d5 rcall .+2606 ; 0x189c <__divmodhi4> e6e: 16 2f mov r17, r22 e70: 0f c0 rjmp .+30 ; 0xe90 <lcdPrintText(char const*, unsigned char, signed char, signed char)+0x68> } Одно хоть радует - при вызове функции есть хоть какая-то польза от восьмибитных параметров - их быстрее загружать :) А дальше всё равно бессмысленное "растягивание" до int... и впустую потраченное время и место во флэш. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aesok 0 27 ноября, 2008 Опубликовано 27 ноября, 2008 (изменено) · Жалоба Но смысла в нём мало - всё равно всё тупо "растягивается" до 16-ти бит :crying: ... даже switch: 6.8.4.2 The switch statement Constraints 1 The controlling expression of a switch statement shall have integer type. А дальше всё равно бессмысленное "растягивание" до int... и впустую потраченное время и место во флэш. x = (unsigned char )(LCD_WIDTH + x - lcdGetStringWidth(text)) / 2 31 000a 4983 std Y+1,r20 32 .LVL1: 33 000c 0E94 0000 call lcdGetStringWidth 34 .LVL2: 35 0010 4981 ldd r20,Y+1 36 0012 405A subi r20,lo8(-(96)) 37 .LVL3: 38 0014 481B sub r20,r24 39 0016 4695 lsr r20 40 0018 4093 0000 sts xx,r20 Анатолий. Изменено 27 ноября, 2008 пользователем aesok Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 27 ноября, 2008 Опубликовано 27 ноября, 2008 · Жалоба А дальше всё равно бессмысленное "растягивание" до int... и впустую потраченное время и место во флэш. Вот именно. switch - хоть и int по стандарту, но если у него аргумент прямо в скобках &0xE0, то никаким стандартом не прикрыть недоточенность компилятора. Аналогично есть вопросы к выражению. Все операнды и результат 8 бит, а в середине выражение вычисляется через 16 бит. Чтото не так. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
msalov 0 27 ноября, 2008 Опубликовано 27 ноября, 2008 · Жалоба Аналогично есть вопросы к выражению. Все операнды и результат 8 бит, а в середине выражение вычисляется через 16 бит. Чтото не так. Это называется Integer promotion - приведение char к int в промежуточных вычислениях, прописано в стандарте. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 27 ноября, 2008 Опубликовано 27 ноября, 2008 · Жалоба Это называется Integer promotion - приведение char к int в промежуточных вычислениях, прописано в стандарте. Ссылку. Чтото я совсем потерялся. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
msalov 0 27 ноября, 2008 Опубликовано 27 ноября, 2008 · Жалоба Ссылку. Чтото я совсем потерялся. ISO/IEC 9899:1999 5.1.2.3 пункт 10 EXAMPLE 2 In executing the fragment char c1, c2; /* ... */ c1 = c1 + c2; the ‘‘integer promotions’’ require that the abstract machine promote the value of each variable to int size and then add the two ints and truncate the sum. Provided the addition of two chars can be done without overflow, or with overflow wrapping silently to produce the correct result, the actual execution need only produce the same result, possibly omitting the promotions. 6.3.1.1 пункт 2 If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.48) All other types are unchanged by the integer promotions. 48) The integer promotions are applied only: as part of the usual arithmetic conversions, to certain argument expressions, to the operands of the unary +, -, and ~ operators, and to both operands of the shift operators, as specified by their respective subclauses. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 27 ноября, 2008 Опубликовано 27 ноября, 2008 · Жалоба Это называется Integer promotion - приведение char к int в промежуточных вычислениях, прописано в стандарте. Но неужели слепое следование стандартам больших машин - это абсолютно правильно и на AVR? Неужели в вышеприведённом примере столь необходимо было следовать такому стандарту? А может существует какая-то опция, позволяющая отключать эту фичу? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 0 27 ноября, 2008 Опубликовано 27 ноября, 2008 · Жалоба Но неужели слепое следование стандартам больших машин - это абсолютно правильно и на AVR? Следование стандартам ВСЕГДА правильно, а вот то, что int на восьмибитовике 1бит - вот это уже НЕ ПРАВИЛЬНОЕ (хотя не противоречащее стандарту) решение принятое когда-то производителями восьмибитовых компиляторов :(, полагаю для тупой совместимости с массовыми на тот момент 16bit-овиками, дабы _бездумно_ :( портировать исходники с 16bit интами. Если int действительно имел максимально естественую для 8bit контроллера разрядность 8bit, то и проблем c этитм не было-бы, как их нет не 16/32bit платформах. А может существует какая-то опция, позволяющая отключать эту фичу? Гипотетически изменить размерность int в хидерах на 8bit и пресобрать все, включая библиотеки. Если авторы компилятора все делали правильно, то должно получиться. А вообще пора завязывать с 8bit :) :) :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 27 ноября, 2008 Опубликовано 27 ноября, 2008 · Жалоба Следование стандартам ВСЕГДА правильно, а вот то, что int на восьмибитовике 1бит - вот это уже НЕ ПРАВИЛЬНОЕ (хотя не противоречащее стандарту) решение принятое когда-то производителями восьмибитовых компиляторов :(, полагаю для тупой совместимости с массовыми на тот момент 16bit-овиками, дабы _бездумно_ :( портировать исходники с 16bit интами. Если int действительно имел максимально естественую для 8bit контроллера разрядность 8bit, то и проблем c этитм не было-бы, как их нет не 16/32bit платформах. Гипотетически изменить размерность int в хидерах на 8bit и пресобрать все, включая библиотеки. Если авторы компилятора все делали правильно, то должно получиться. А вообще пора завязывать с 8bit :) :) :) Понятно, спасибо :) Оставим это как дань стандартам и одновременно лень производителей :) Почти во всём при компиляции своего проекта уже разобрался. Ещё вот беспокоят такие ворнинги: only initialized variables can be placed into program memory area на стоки, подобные вот этим: if (statusRx.lock_err) usartSendString(PSTR("Receiver LOCKED!")); const char PROGMEM fntable[] = "!\"%`()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^"; то есть ругается на все PSTR() и на все PROGMEM. Чего такого неправильного я там сделал? :07: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alx2 0 27 ноября, 2008 Опубликовано 27 ноября, 2008 · Жалоба void lcdPrintText(PGM_P text, byte flags, signed char x, signed char y) switch(flags & 0xe0) { ... Но смысла в нём мало - всё равно всё тупо "растягивается" до 16-ти бит :crying: ... даже switch: { switch(flags & 0xe0) e3a: 70 e0 ldi r23, 0x00; 0 e3c: 60 7e andi r22, 0xE0; 224 e3e: 70 70 andi r23, 0x00; 0 e40: 60 38 cpi r22, 0x80; 128 e42: 71 05 cpc r23, r1 Как ты получил такой код??? =8-( ) Вот такой тестовый пример: int do_something(void); void fff(char flags) { switch(flags & 0xe0) { case 0x80: do_something(); } } у меня компилируется вот в такой код: fff: /* prologue: function */ /* frame size = 0 */ andi r24,lo8(-32) cpi r24,lo8(-128) brne .L4 rcall do_something .L4: ret при любой -O отличной от -O0. gcc-4.3.1. Скажи, пожалуйста, версию своего компилятора, с какой оптимизацией компилировался код и как определено byte. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 27 ноября, 2008 Опубликовано 27 ноября, 2008 · Жалоба Понятно, спасибо :) Оставим это как дань стандартам и одновременно лень производителей :) Стандарт не запрещает оптимизатору не расширять char до int если результат останется одинаковым. Или расширить, но потом все лишнее выкинуть. то есть ругается на все PSTR() и на все PROGMEM. Чего такого неправильного я там сделал? :07: Это не вы, это они намудрили в компиляторе. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться