|
|
  |
Стиль программирования на Си, описание функции |
|
|
|
Apr 2 2008, 20:31
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Apr 2 2008, 23:30)  Вы знаете? Тогда пример в студию...... Да пожалуйста, WinAvr20060421, на IAR тоже как-то проверял, чуть получше но тоже не блеск: Код #include <avr/io.h>
volatile unsigned char al=0xFF; volatile unsigned char ah=0xFF; volatile unsigned char Pb,Pc,Pd;
int main() { unsigned char pb,pc,pd;
unsigned char tmpl = al; unsigned char tmph = ah;
//------------ Вариант N1 ("правильный") pb = (tmph & 0b10000000) | ((tmph & 0b01110000) >> 1) | ((tmph & 0b00001100) >> 2); pc = ((tmph & 0b00000011) << 2) | ((tmpl & 0b11000000) >> 6); pd = tmpl <<2; //----- сохраняем результат Pb = pb; Pc = pc; Pd = pd;
tmpl = al; tmph = ah;
//------------ Вариант N2 ("неправильный :) ") pd = (tmpl << 2); pc = tmph & 0b01111100; pc >>= 1; pb = (tmph & 0b10000000); pb |= (pc & 0b00111000); pc &= 0b00000110; pc >>= 1; pb |= pc; pc = (tmph&0b00000011); pc <<= 2; pd = tmpl >> 6; pc |= pd; pd = tmpl << 2; //----- сохраняем результат Pb = pb; Pc = pc; Pd = pd;
//---------------------------
while (1);
} результат компиляции: Код pb = (tmph & 0b10000000) | ((tmph & 0b01110000) >> 1) | ((tmph & 0b00001100) >> 2); 6c: 24 2f mov r18, r20 6e: 33 27 eor r19, r19 70: c9 01 movw r24, r18 72: 80 77 andi r24, 0x70; 112 74: 90 70 andi r25, 0x00; 0 76: 95 95 asr r25 78: 87 95 ror r24 7a: 40 78 andi r20, 0x80; 128 7c: 48 2b or r20, r24 7e: c9 01 movw r24, r18 80: 8c 70 andi r24, 0x0C; 12 82: 90 70 andi r25, 0x00; 0 84: 95 95 asr r25 86: 87 95 ror r24 88: 95 95 asr r25 8a: 87 95 ror r24 8c: 48 2b or r20, r24 pc = ((tmph & 0b00000011) << 2) | ((tmpl & 0b11000000) >> 6); 8e: 23 70 andi r18, 0x03; 3 90: 30 70 andi r19, 0x00; 0 92: 22 0f add r18, r18 94: 33 1f adc r19, r19 96: 22 0f add r18, r18 98: 33 1f adc r19, r19 9a: 85 2f mov r24, r21 9c: 99 27 eor r25, r25 9e: 36 e0 ldi r19, 0x06; 6 a0: 96 95 lsr r25 a2: 87 95 ror r24 a4: 3a 95 dec r19 a6: e1 f7 brne .-8 ; 0xa0 <main+0x44> a8: 28 2b or r18, r24 pd = tmpl <<2; aa: 55 0f add r21, r21 ac: 55 0f add r21, r21 Код pd = (tmpl << 2); pc = tmph & 0b01111100; c2: 24 2f mov r18, r20 c4: 2c 77 andi r18, 0x7C; 124 pc >>= 1; c6: 26 95 lsr r18 pb = (tmph & 0b10000000); c8: 94 2f mov r25, r20 ca: 90 78 andi r25, 0x80; 128 pb |= (pc & 0b00111000); cc: 82 2f mov r24, r18 ce: 88 73 andi r24, 0x38; 56 d0: 98 2b or r25, r24 pc &= 0b00000110; d2: 26 70 andi r18, 0x06; 6 pc >>= 1; d4: 26 95 lsr r18 pb |= pc; d6: 92 2b or r25, r18 pc = (tmph&0b00000011); d8: 24 2f mov r18, r20 da: 23 70 andi r18, 0x03; 3 pc <<= 2; dc: 22 0f add r18, r18 de: 22 0f add r18, r18 pd = tmpl >> 6; e0: 85 2f mov r24, r21 e2: 82 95 swap r24 e4: 86 95 lsr r24 e6: 86 95 lsr r24 e8: 83 70 andi r24, 0x03; 3 pc |= pd; ea: 28 2b or r18, r24 pd = tmpl << 2; ec: 55 0f add r21, r21 ee: 55 0f add r21, r21 ИТОГО: "Правильный" 21 слов 58 тактов "Неправильный" 17 слов 23 такта Выводы делаем сами
|
|
|
|
|
Apr 2 2008, 21:22
|

Частый гость
 
Группа: Свой
Сообщений: 160
Регистрация: 17-03-08
Из: Мурманская
Пользователь №: 35 989

|
На СИ, правильно когда по-больше зелени (#define), а на C++, а тем более шарпе, - когда этого по-меньше. Шучу. Важно чтобы программа работала, менее важно - как она написана. Если расчитывать что кому-то придется в этом коде разбираться, то желательно писать коментарии. Даже самому приходится иногда разбирая старый код вспоминать что же там имелось ввиду. Мне нравится стиль Microsoft, лучше трудно придумать.
--------------------
Демократия - это когда считается, что два дурака лучше одного умного Суверенная демократия - это когда считается, что один дурак лучше двух дураков
|
|
|
|
|
Apr 2 2008, 21:51
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(singlskv @ Apr 2 2008, 23:31)  Да пожалуйста, WinAvr20060421, на IAR тоже как-то проверял, чуть получше но тоже не блеск: Ну и где обещанная экономия от Цитата ...правильно разбить эти 3 оператора на нужное количество строк... Налицо ДВА РАЗНЫХ АЛГОРИТМА, а не описание одного и того-же "разным количеством строк". Кроме того, посмею предположить, что под нормально оптимизирующим компилятором разница будет в пару команд максимум. Цитата Выводы делаем сами Сделал  Цитата(AlexKLm @ Apr 3 2008, 00:22)  Мне нравится стиль Microsoft, лучше трудно придумать. Трудно придумать стиль в котором больше жертв принесено стилю ради собственно абсолютно формального стиля.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Apr 2 2008, 21:55
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Apr 3 2008, 01:47)  Налицо ДВА РАЗНЫХ АЛГОРИТМА, с ОДИНАКОВЫМ результатом, и принципиально не различающимся методом вычислений, + если Вы не обратили внимание, во втором варианте операции на одну больше  Цитата Кроме того, посмею предположить, что под нормально оптимизирующим компилятором разница будет в пару команд максимум. покажите результат компиляции...
|
|
|
|
|
Apr 2 2008, 22:08
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(singlskv @ Apr 3 2008, 00:55)  покажите результат компиляции... А самому? Думаете поленюсь copy-paste и убрать отрыжки древних ассемблеров не имеющих препроцессоров? Ладно: Код // 19 void m1(void) m1: // 20 { // 21 unsigned char pb,pc,pd; // 22 // 23 unsigned char tmpl = al; LDI R30, LOW(al) LDI R31, (al) >> 8 LD R19, Z // 24 unsigned char tmph = ah; LDD R16, Z+1 // 25 // 26 //------------ Вариант N1 ("правильный") // 27 pb = ( tmph & 0x80 )|( (tmph & 0x70) >> 1 )|( (tmph & 0xC0) >> 2 ); // 28 pc = ((tmph & 0x03) << 2 )|( (tmpl & 0xC0) >> 6 ); // 29 pd = tmpl <<2; // 30 // 31 //----- сохраняем результат // 32 Pb = pb; MOV R18, R16 ANDI R18, 0x80 MOV R17, R16 ANDI R17, 0x70 ASR R17 OR R18, R17 MOV R17, R16 ANDI R17, 0xC0 LSR R17 LSR R17 OR R18, R17 STD Z+2, R18 // 33 Pc = pc; ANDI R16, 0x03 LSL R16 LSL R16 LDI R17, 4 MUL R19, R17 OR R16, R1 STD Z+3, R16 // 34 Pd = pd; LSL R19 LSL R19 STD Z+4, R19 // 35 // 36 } RET
// 38 void m2(void) m2: // 39 { // 40 // 41 unsigned char pb,pc,pd; // 42 // 43 unsigned char tmpl = al; LDI R30, LOW(al) LDI R31, (al) >> 8 LD R20, Z // 44 unsigned char tmph = ah; LDD R18, Z+1 // 45 // 46 //------------ Вариант N2 ("неправильный :) ") // 47 pd = (tmpl << 2); // 48 // 49 pc = tmph & 0x7C; // 50 pc >>= 1; MOV R17, R18 ANDI R17, 0x7C LSR R17 // 51 // 52 pb = (tmph & 0x80); // 53 pb |= (pc & 0x38); // 54 pc &= 0x06; // 55 pc >>= 1; // 56 pb |= pc; // 57 pc = tmph & 0x03; // 58 pc <<= 2; // 59 pd = tmpl >> 6; // 60 pc |= pd; // 61 pd = tmpl << 2; // 62 //----- сохраняем результат // 63 Pb = pb; MOV R19, R18 ANDI R19, 0x80 MOV R16, R17 ANDI R16, 0x38 OR R19, R16 ANDI R17, 0x06 LSR R17 OR R19, R17 STD Z+2, R19 // 64 Pc = pc; ANDI R18, 0x03 LSL R18 LSL R18 LDI R16, 4 MUL R20, R16 OR R18, R1 STD Z+3, R18 // 65 Pd = pd; LSL R20 LSL R20 STD Z+4, R20 // 66 } RET P.S. Получилось, что все ухищрения яйца выеденного не стоят....
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Apr 2 2008, 22:32
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(singlskv @ Apr 2 2008, 23:55)  с ОДИНАКОВЫМ результатом, и принципиально не различающимся методом вычислений, Но тем не менее разных алгоритма :-) Кстати, если переписать это так, как привычно мне  - сначала сдвиги, потом маскирования (так как сдвиги С часто компилируются в ассемблерные сдвиги с последующим маскированием, маскирования, разделённые сдвигом, часто остаются, хотя они и ихбыточные, а вот два маскирования подряд компиляторы как правило объединяют  ), да и мне лично проще анализировать "сначала сдвиг, потом маскирование" Код __asm__ volatile ("nop" ::); // так удобнее искать потом границы фрагментов
tmpl = al; tmph = ah;
pb = (tmph & 0b10000000) | ((tmph >> 1) & 0b00111000) | ((tmph >> 2) & 0b00000011); pc = ((tmph << 2) & 0b00001100) | ((tmpl >> 6) & 0b00000011); pd = tmpl <<2; //----- Pb = pb; Pc = pc; Pd = pd; __asm__ volatile ("nop" ::); то особой разницы-то и под gcc не видно... Код /* #APP */ nop /* #NOAPP */ lds r19,al lds r25,ah mov r18,r25 lsr r18 andi r18,lo8(56) mov r24,r25 lsr r24 lsr r24 andi r24,lo8(3) or r18,r24 mov r24,r25 andi r24,lo8(-128) or r18,r24 lsl r25 lsl r25 andi r25,lo8(12) mov r24,r19 swap r24 lsr r24 lsr r24 andi r24,lo8(3) or r25,r24 lsl r19 lsl r19 sts Pb,r18 sts Pc,r25 sts Pd,r19 /* #APP */ nop /* #NOAPP */ lds r20,al lds r25,ah mov r24,r25 andi r24,lo8(124) lsr r24 mov r19,r24 andi r19,lo8(56) mov r18,r25 andi r18,lo8(-128) or r19,r18 andi r24,lo8(6) lsr r24 or r19,r24 andi r25,lo8(3) lsl r25 lsl r25 mov r24,r20 swap r24 lsr r24 lsr r24 andi r24,lo8(3) or r25,r24 sts Pb,r19 sts Pc,r25 lsl r20 lsl r20 sts Pd,r20 .L2: rjmp .L2 Цитата(zltigo @ Apr 2 2008, 23:51)  Трудно придумать стиль в котором больше жертв принесено стилю ради собственно абсолютно формального стиля. +1 У меня мозги в трубочку сворачиваются и через уши вылазят, когда я вижу идентификаторы в стиле ВЗБЗД взбздНуть; Их трудно произнести и, как следствие, ими трудно мыслить. Зато вылет за правый край экрана даже при отступах по 2 символа (о ужас дельфийский) гарантирован даже на операторах средней сложности. Итого народ пишет исключительно простые, но софт от этого ни компактнее, ни лучше не становится. Как, впрочем, не становится лучше и обычный текст, не содержащий совершенно сложноподчинённых предложений, а состоящий из одних простых ("зато нет глюкодрома с запятыми"  ).
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 2 2008, 22:37
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Apr 3 2008, 02:08)  и убрать отрыжки древних ассемблеров не имеющих препроцессоров? это не отрыжки, это удобство для данной конкретной задачки, по битикам видно что куда попадает, но это просто специфика... Кстати Вы вот так и ошиблись при переводе из двоичного представления в 16x вот так: (tmph & 0b10000000)......(tmph & 0b01110000).......(tmph & 0b00001100 ) сразу же видно что взяли нужные битики, а вот так нифига не видно: ( tmph & 0x80 )........(tmph & 0x70)..........(tmph & 0xC0 ) Цитата Я же говорю, пробовал, раньше код был намного хуже. Какая версия ? С таким выходом - убедили!
|
|
|
|
|
Apr 2 2008, 22:46
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(singlskv @ Apr 3 2008, 00:37)  Я же говорю, пробовал, раньше код был намного хуже. Какая версия ? Мой вариант - 20071221, но и на 20060421 полный паритет между вариантами "мой самый правильный"  и "неправильный" Код /* #APP */ nop /* #NOAPP */ lds r21,al lds r20,ah mov r25,r20 andi r25,lo8(-128) mov r24,r20 lsr r24 andi r24,lo8(56) or r25,r24 mov r24,r20 lsr r24 lsr r24 andi r24,lo8(3) or r25,r24 lsl r20 lsl r20 andi r20,lo8(12) mov r24,r21 swap r24 lsr r24 lsr r24 andi r24,0x3 or r20,r24 lsl r21 lsl r21 sts Pb,r25 sts Pc,r20 sts Pd,r21 /* #APP */ nop /* #NOAPP */ lds r21,al lds r20,ah mov r18,r20 andi r18,lo8(124) lsr r18 mov r25,r20 andi r25,lo8(-128) mov r24,r18 andi r24,lo8(56) or r25,r24 andi r18,lo8(6) lsr r18 or r25,r18 mov r18,r20 andi r18,lo8(3) lsl r18 lsl r18 mov r24,r21 swap r24 lsr r24 lsr r24 andi r24,0x3 or r18,r24 lsl r21 lsl r21 sts Pb,r25 sts Pc,r18 sts Pd,r21 .L2: rjmp .L2 У меня на компе и 20060421 до сих пор стоит, на всякий случай.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 2 2008, 23:25
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(ReAl @ Apr 3 2008, 02:32)  Кстати, если переписать это так, как привычно мне  - сначала сдвиги, потом маскирования (так как сдвиги С часто компилируются в ассемблерные сдвиги с последующим маскированием, маскирования, разделённые сдвигом, часто остаются, хотя они и ихбыточные, а вот два маскирования подряд компиляторы как правило объединяют  ), да и мне лично проще анализировать "сначала сдвиг, потом маскирование" Так собственно мы и сделали одно и тоже но разными средствами Цитата(ReAl @ Apr 3 2008, 02:46)  Мой вариант - 20071221, но и на 20060421 полный паритет между вариантами "мой самый правильный"  и "неправильный" Мне просто почему-то удобнее мыслить сначала маскированием а потом сдвигами, а 20060421 ну никак не хотел ко мне привыкать  Цитата(ReAl @ Apr 3 2008, 02:46)  У меня на компе и 20060421 до сих пор стоит, на всякий случай. OFF: Кстати, может быть у Вас есть ответ на вот этот вопрос: http://electronix.ru/forum/index.php?showtopic=26519Никто так ничего толком и не ответил, пару раз неприятно натыкался, кроме как ручной тасовкой команд решения не знаю...
|
|
|
|
|
Apr 2 2008, 23:45
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(singlskv @ Apr 3 2008, 00:55)  Так собственно мы и сделали одно и тоже но разными средствами Так я и не говорю, что сделано что-то совсем другое (в отличие от варианта в 10 строк), просто неболшое переупорядочивание операций под мою голову  Цитата(singlskv @ Apr 3 2008, 00:55)  Мне просто почему-то удобнее мыслить сначала маскированием а потом сдвигами, Если выделяется какое-то битовое поле в "целочисленную переменную", то "сначала сдвиг" показывает, где поле начиналось, а "потом маскирование" это просто число единичек справа, равное длине поля, т.е. Код fld = (var >> field_start) & ((1 << field_len) - 1); А если сначала маскирование, то выражение становится запутаннее. Поскольку мне чаще приходилось именно получать нужные поля начиная с 0-ого бита переменной, в которую они заносились - мне привычнее такой вариант. Кстати, господа хорошие, что-то мне кажется, что этот вариант: Код unsigned char tmph = ah; unsigned int tmp = (tmph<<8) | al; tmp <<= 2; pb = tmph & 0b10000000; tmph >>= 1; pb |= tmph & 0b00111000; tmph >>= 1; pb |= tmph & 0b00000011; //----- Pb = pb; Pc = (tmp>>8) & 0x0F; Pd = tmp; Самый понятный с точки зрения "а что, собственно, делается". И даже несмотря на традиционно плохонькую реализацию в gcc склеивания слова из двух байтов и выделения старшего байта слова (после оптимизатора остаются рудименты "integer promotion") - он находится "где-то там же" по длине. Код lds r20,ah lds r24,al mov r18,r20; во аж сколько заняло ldi r19,lo8(0); unsigned int tmp = (tmph<<8) | al; mov r19,r18; clr r18; ldi r25,lo8(0); or r18,r24; or r19,r25; lsl r18 rol r19 lsl r18 rol r19 mov r24,r20 lsr r24 mov r25,r24 andi r25,lo8(56) andi r20,lo8(-128) or r25,r20 lsr r24 andi r24,lo8(3) or r25,r24 sts Pb,r25 mov r24,r19; а это недочищенный хвосты clr r25; (tmp>>8) & 0x0F; andi r24,lo8(15) sts Pc,r24 sts Pd,r18 Если бы оптимизатор был тут немного умнее, или если применить макрос-вставку Код #define HILOTO16(hi, lo) ({ \ unsigned int __result; \ __asm__ ( " mov %B0,%1 \n" : "=r" (__result) : "r" (hi), "0" (lo) ); \ __result; }) ... ... tmph = ah; unsigned int tmp = HILOTO16(tmph, al); tmp <<= 2; pb = tmph & 0b10000000; tmph >>= 1; pb |= tmph & 0b00111000; tmph >>= 1; pb |= tmph & 0b00000011; //----- Pb = pb; Pc = (tmp>>8) & 0x0F; Pd = tmp; То по сравнению с "неправильным", казалось бы "уоптимизированным вусмерть" и практически непонятным вариантом выходит гораздо короче: Код lds r25,ah lds r18,al ; /* #APP */ mov r19,r25; это то, что вышло из макроса HILOTO16(), /* #NOAPP */; правильный оптимизатор должен был бы сделать так же. lsl r18 rol r19 lsl r18 rol r19 mov r24,r25 lsr r24 mov r20,r24 andi r20,lo8(56) andi r25,lo8(-128) or r20,r25 lsr r24 andi r24,lo8(3) or r20,r24 sts Pb,r20 mov r24,r19; это уж ладно clr r25; andi r24,lo8(15) sts Pc,r24 sts Pd,r18 Цитата(singlskv @ Apr 3 2008, 01:25)  OFF: Кстати, может быть у Вас есть ответ на вот этот вопрос: http://electronix.ru/forum/index.php?showtopic=26519Никто так ничего толком и не ответил, пару раз неприятно натыкался, кроме как ручной тасовкой команд решения не знаю... Ответ таков - если это жутко критичное по скорости место - вписать ассемблерную вставку и забыть. Иначе - забить. Ну хуже оптимизаторы, чем они в принципе могут быть, хуже. Если постоянно копаться в выдаче компилятора и страдать от недооптимизации - то лучше перейти на асм. Кстати, в большинстве случаев -Os для AVR даёт лучше код, чем -O2 :-)
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 3 2008, 05:53
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(singlskv @ Apr 3 2008, 01:37)  это не отрыжки, это удобство для данной конкретной задачки, по битикам видно что куда попадает, но это просто специфика... Да ничего не видно, при "видно" не ошибся-бы,даже в 2 часа ночи... А тут даже на 8bit глазоломка, а уж на 32  Цитата сразу же видно что взяли нужные битики, Более-менее видно когда такое написано,хоть на ASM, хоть на C, как минимум так: Код ( tmph & BIT7 )........(tmph & (BIT6|BIT5|BIT4)).......... а вобще надо давать осмысленные имена Код ( tmph & B_SIGN )........(tmph & M_LEVEL).......... Цитата Я же говорю, пробовал, раньше код был намного хуже. Какая версия ? IAR 5.10, но, полагаю, и на 4.x будет тот-же результат.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Apr 3 2008, 08:28
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(SasaVitebsk @ Apr 3 2008, 09:23)  Вот я и говорю, что результат практически тот же при оптимизации, а при отладке неудобно большие громоздкие формулы (в приведенных примерах вполне нормальные). Поэтому здоровую формулу, с возможностью неоднозначного вычисления (точнее требующую специального разбора порядка вычисления), лучше разбить на пару однозначных. Компилятору всё равно, а человеку удобнее. Я бы сказал, что как раз этому критерию приведенный пример не отвечает абсолютно. "неправильный" вариант гораздо труднее для понимания, и чем первый "правильный", и чем мой с 16-битной переменной. Микс из элементарных операций с разными переменными, который нужно много раз прочесть туда-назад, чтобы понять в чём дело. Он выглядит скорее как "а вот я умнее компилятора и напишу на С, но как бы на асме (всё равно не имея всех асмовых возможностей, кстати) и оно будет компактнее и работать быстрее", а не как "в таком виде оно понятнее человеку".
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|