GCC - поясните.

Hello, All!

Hесколько вопросов появилось после юзанья сабж. Возможно глупых. Исходники на работе, поэтому на пальцах, но если понадобятся притащу. 1. В функции main есть что-то подобное:

union { uint8_t byte; struct { uint8_t first:1; uint8_t second:1; }; }flags;

...... if (flags.first==1) { cli(); flags.first=0; sei(); ..... здесь строчек 5-10 в том числе вызовы функций cli(); flags.second=1; sei(); } ......

Компилятор при проверке флага first загружает union в регистр а в конце if'а устанавливает в этом регистре бит и сохраняет в памяти. volatile конечно спасает, но для меня это несколько неожиданно - соседнии строчки еще туда-сюда, но чтоб через 5-10... 2. В коротенькой функции использую три раза _delay_ms(). При входе в функцию компилятор заранее инициализирует значения для делау в шести регистрах. К тому же несколько регистров обнуляет командой - mov rx,r1 а несколько ldi rx,0.

Мне не понятно, насколько естественно такое поведение компилятора. Или у меня какая-то кривая версия загружена? Да, уровень оптимизации - s.

По-поводу компилятора возникли подозрения из-за того, что сегодня вернулся к программе которую отложил пару недель назад. Программа перестала делать то, что выполняла раньше. Разобраться не успел, так как было это под конец работы. Hе могу вспомнить когда именно, но недавно скачивал более свежую версию gcc, так как переставлял винду (ХР). Какую версию лучше установить?

With best regards, Igor. Time: 18:31 Date: 01 Мар 06

Reply to
Igor Ulanov
Loading thread data ...

Привет Igor!

01 Mar 06 18:31, Igor Ulanov писал All:

IU> 1. В функции main есть что-то подобное:

IU> ......

IU> Компилятор при проверке флага first загружает union в регистр а в IU> конце if'а устанавливает в этом регистре бит и сохраняет в памяти.

Вполне логично. Оптимальнее, конечно, вообще flags в память не складывать, все операции с ней выполнять в регистре, но, видимо, не получилось. Hе бывает идеальных оптимизаторов.

IU> volatile конечно спасает,

От чего спасает? От слишком оптимального кода? :) Результат-то вычислений все равно одинаковый, а лишнее складывание в память и доставание из памяти - бессмысленная трата кода.

IU> но для меня это несколько неожиданно - соседнии строчки еще IU> туда-сюда, но чтоб через 5-10...

Hадеюсь, это приятная неожиданность. А вопрос-то в чем?

IU> 2. В коротенькой IU> функции использую три раза _delay_ms(). При входе в функцию IU> компилятор IU> заранее инициализирует значения для делау в шести регистрах. К тому же IU> несколько регистров обнуляет командой - mov rx,r1 а несколько ldi IU> rx,0.

IU> Мне не понятно, насколько естественно такое поведение компилятора.

Покажи пример кода. Со слов что-либо комментировать трудно. Опять же, не следует ожидать от оптимизатора абсолютно идеального результата. Если на счету каждая инструкция, пиши на ассемблере.

IU> Или у меня какая-то кривая версия загружена?

В сказанном тобой никакого криминала не вижу.

IU> Программа перестала делать то, что выполняла раньше.

Даю 99.9% за то, что ошибка в программе.

IU> Разобраться не успел, так как было это под конец работы. Hе могу IU> вспомнить когда именно, но недавно скачивал более свежую версию gcc, IU> так как переставлял винду (ХР). Какую версию лучше установить?

3.4.5 работает без нареканий. Четвертую ветку пока не пробовал.

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Северо-Кавказская межрегиональная ассоциация анонимных соискателей.

Reply to
Alex Mogilnikov

Имеет полное право. Ведь в коде функции к flags нет обращения. Другое дело, что использование "флагов" вообще дурная идея, чаще всего, исключая редкие исключительные случаи. Лучше ввести понятие "состояние" и хранить его в одной переменной. Багов резко поубавится.

Это его компиляторово дело, что и в каких регистрах окажется. Так что я не понимаю сути вопроса.

99% ошибок компилятора -- ошибки в подсовываемых ему программах.
Reply to
Kirill Frolov

Hello, Kirill!

(02 Мар 06 14:33), Kirill Frolov писАл Igor Ulanov: KF> Имеет полное право. Ведь в коде функции к flags нет обращения. Да, понятно. Сам виноват. Просто хотел услышать подтверждение.

KF> Другое дело, что использование "флагов" вообще дурная идея, чаще KF> всего, исключая редкие исключительные случаи. Лучше ввести понятие KF> "состояние" и хранить его в одной переменной. Багов резко поубавится. Второй раз слышу такое утверждение - хотелось бы услышать обоснование. Мне намного проще работать с флагами, чем с состояниями, поэтому хотелось бы понять где прячутся баги. Про переносимость согласен. А еще? И кстати а как работать с состояниями? if (flags & mask_first), flags |= (1<<n_bit_first)? Или можно как-то проще?

With best regards, Igor. Time: 18:22 Date: 02 Мар 06

Reply to
Igor Ulanov

Hello, Alex!

(02 Мар 06 00:58), Alex Mogilnikov писАл Igor Ulanov: AM> Покажи пример кода. Со слов что-либо комментировать трудно. Опять AM> же, не следует ожидать от оптимизатора абсолютно идеального AM> результата. Если на счету каждая инструкция, пиши на ассемблере.

В том конкретном случае оптимальность не на первом месте. Вот С: uint8_t Read_byte_microlan(void) { // функция чтения байта с линиии microlan uint8_t i,byte;

byte=0; for (i=0;i<8;i++) { byte=byte>>1; cli(); microlan_port_down(); _delay_us(4); microlan_port_up(); _delay_us(13); if (PINB & 0x01) byte+=0x80; sei(); _delay_ms(0.06); } return (byte); }

Вот результат компиляции: uint8_t Read_byte_microlan(void) { 1fa: ef 92 push r14 1fc: ff 92 push r15 1fe: 0f 93 push r16 200: 1f 93 push r17 202: cf 93 push r28 204: df 93 push r29 206: 70 e0 ldi r23, 0x00 ; 0 208: 83 e1 ldi r24, 0x13 ; 19 20a: e8 2e mov r14, r24 20c: f1 2c mov r15, r1 20e: 01 2d mov r16, r1 210: 11 2d mov r17, r1 212: 2f e3 ldi r18, 0x3F ; 63 214: 30 e0 ldi r19, 0x00 ; 0 216: 40 e0 ldi r20, 0x00 ; 0 218: 50 e0 ldi r21, 0x00 ; 0 21a: ad ed ldi r26, 0xDD ; 221 21c: b0 e0 ldi r27, 0x00 ; 0 21e: c0 e0 ldi r28, 0x00 ; 0 220: d0 e0 ldi r29, 0x00 ; 0 222: 67 e0 ldi r22, 0x07 ; 7

22a: 8e 2d mov r24, r14 22c: 8a 95 dec r24 22e: f1 f7 brne .-4 ; 0x22c 230: b8 98 cbi 0x17, 0 ; 23 232: 82 2f mov r24, r18 234: 8a 95 dec r24 236: f1 f7 brne .-4 ; 0x234 238: b0 99 sbic 0x16, 0 ; 22 23a: 70 58 subi r23, 0x80 ; 128 23c: 78 94 sei 23e: 8a 2f mov r24, r26 240: 9b 2f mov r25, r27 242: 01 97 sbiw r24, 0x01 ; 1 244: f1 f7 brne .-4 ; 0x242 246: 61 50 subi r22, 0x01 ; 1 248: 67 ff sbrs r22, 7 24a: ec cf rjmp .-40 ; 0x224 24c: 87 2f mov r24, r23 24e: 99 27 eor r25, r25 250: 87 fd sbrc r24, 7 252: 90 95 com r25 254: df 91 pop r29 256: cf 91 pop r28 258: 1f 91 pop r17 25a: 0f 91 pop r16 25c: ff 90 pop r15 25e: ef 90 pop r14 260: 08 95 ret

В общем-то конечно терпимо, просто видимо наложилось одно на другое, плюс конец рабочего дня...

IU>> Программа перестала делать то, что выполняла раньше. AM> Даю 99.9% за то, что ошибка в программе. Да, так и оказалось. Забыл, что начал изменять программу, когда оторвали от нее. Вчера SVN поставил, поэтому надеюсь, что от подобных случаев буду застрахован. AM> 3.4.5 работает без нареканий. Четвертую ветку пока не пробовал. У меня оказывается еще старее - 3.4.3

Спасибо за ответ. В общем-то сам во всем виноват, но вчера под конец работы, когда "рабочая" программа перестала работать поверил бы пожалуй и в барабашек:)

With best regards, Igor. Time: 18:02 Date: 02 Мар 06

Reply to
Igor Ulanov

Привет Igor!

02 Mar 06 19:34, Igor Ulanov писал Alex Mogilnikov:

AM>> Покажи пример кода. Со слов что-либо комментировать трудно. AM>> Опять же, не следует ожидать от оптимизатора абсолютно идеального AM>> результата. Если на счету каждая инструкция, пиши на ассемблере.

IU> В том конкретном случае оптимальность не на первом месте. IU> Вот С: IU> uint8_t Read_byte_microlan(void) IU> { ....... IU> }

IU> Вот результат компиляции: IU> uint8_t Read_byte_microlan(void) IU> { ......

В исходном сишном коде я насчитал семь вызовов функций, а в ассемблерном коде не вижу ни одного. Ты что, объявил все эти функции инлайновыми? Как-то это не согласуется с оптимизации по размеру... И ассемблерный текст какой-то странный, не похож на то, что обычно генерит gcc. Вот какой код получился у меня:

Read_byte_microlan: /* prologue: frame size=0 */ push r17 push r28 /* prologue end (size=2) */ ldi r28,lo8(0) ldi r17,lo8(7) .L6: lsr r28 rcall cli rcall microlan_port_down ldi r24,lo8(4) ldi r25,hi8(4) rcall _delay_us rcall microlan_port_up ldi r24,lo8(13) ldi r25,hi8(13) rcall _delay_us lds r24,PINB sbrc r24,0 subi r28,lo8(-(-128)) .L5: rcall sei ldi r22,lo8(0x3d75c28f) ldi r23,hi8(0x3d75c28f) ldi r24,hlo8(0x3d75c28f) ldi r25,hhi8(0x3d75c28f) rcall _delay_ms subi r17,lo8(-(-1)) sbrs r17,7 rjmp .L6 mov r24,r28 clr r25 /* epilogue: frame size=0 */ pop r28 pop r17 ret /* epilogue end (size=3) */

IU> При входе в функцию компилятор заранее инициализирует значения для IU> делау в шести регистрах. К тому же несколько регистров обнуляет IU> командой - mov rx,r1 а несколько ldi rx,0.

По-поводу этих двух команд: они дают одинаковый результат, т.к. avr-gcc обычно в r1 держит 0, и в коде так его и называет - __zero_reg__. Кстати, у меня он им ни разу не воспользовался. Откуда берется ldi rx,0 из моего варианта кода понятно - это загрузка старшего байта константы.

IU> В общем-то конечно терпимо, просто видимо наложилось одно на IU> другое, плюс конец рабочего дня...

IU>>> Программа перестала делать то, что выполняла раньше. AM>> Даю 99.9% за то, что ошибка в программе. IU> Да, так и оказалось. Забыл, что начал изменять программу, когда IU> оторвали от нее. Вчера SVN поставил, поэтому надеюсь, что от подобных IU> случаев буду застрахован.

Сделал ты все правильно, но застрахован не будешь. :) Во-первых, свои ошибки вообще трудно заметить. Во-вторых, ошибка может быть весьма хитрой. В-третьих, она может оказаться вообще не в твоем коде, а в какой-нибудь библиотеке. Вот, кажется, при переходе с gcc-3.1 на gcc-3.3 я получил мертвое зависание при старте давно отлаженной программы. Оказалось, проблема была в библиотечном ctrend.c, имеющем такое содержание:

======== crtend.c ======== typedef void (*fptr)(void);

static fptr ctor_end[1] __attribute__((section(".ctors"), __unused__)) = { 0 }; static fptr dtor_end[1] __attribute__((section(".dtors"), __unused__)) = { 0 }; ==========================

Поскольку ctor_end и dtor_end нигде не использовались, оптимизатор gcc-3.2 их просто выкинул (gcc-3.1 оставлял), в результате таблица конструкторов глобальных объектов оказалась без завершающего нуля, и стартап вис при попытке выполнить мусор.

AM>> 3.4.5 работает без нареканий. Четвертую ветку пока не пробовал. IU> У меня оказывается еще старее - 3.4.3

Фигня, некоторые до сих пор 2.96 используют. А вот четвертую ветку любопытно попробовать, но, наверное, для ARM, т.к. avr я уже практически не использую...

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Владею дыроколом на уровне пользователя.

Reply to
Alex Mogilnikov

Вопрос не в переносимости. Это вообще вопрос не уровня кодирования. Суть в том, что проще, для программиста, иметь одну переменную однозначно определяющую состояние своим числовым значением (1, 2... N), чем десяток переменных вместо того. И, соответственно, определять реакцию на различные события для каждого из N состояний по-отдельности. Удобно, что в любой момент времени известно, в каком состоянии находится система и известны все её реакции на все возможные события. Работа системы легко протоколируется. Возможно аналитически проверить правильность системы в целом. С флагами это всё конечно тоже так, но учесть все флаги с их 2^n числом состояний, что типично много больше N -- сложно. Хотя при желании оно преобразуется к описанному выше варианту. Можно сказать, что с состояниями получается громоздкий код. Или число состояний невообразимо велико. Но в первом случае возможны различные техники оптимизации, вроде объединения кода совместно используемого в разных состояниях. Или оптимизации автомата. Во втором случае эквиэвалентный автомат можно разбить на несколько параллельных или вложенных, реализующих свою более узкую задачу -- с этого даже стоит начинать.

Самое простое -- оператор switch, как показано ниже. Возможно также введение функций, обрабатывающей события в каждом конкретном состоянии. Более подробно разные варианты можно подсмотреть на

formatting link

switch (state) { case 1: blablabla; ... break; case 2: blablabla; ... break; ... }

Reply to
Kirill Frolov

Hello, Kirill! You wrote to Igor Ulanov on Fri, 03 Mar 2006 10:39:36 +0500:

KF> Суть в том, что проще, для программиста, иметь одну KF> переменную однозначно определяющую состояние своим числовым KF> значением (1, 2... N), чем десяток переменных вместо того. KF> И, соответственно, определять реакцию на различные события для KF> каждого из N состояний по-отдельности. Удобно, что в любой момент KF> времени известно, в каком состоянии находится система и известны KF> все её реакции на все возможные события. Работа системы легко KF> протоколируется. Возможно аналитически проверить правильность KF> системы в целом.С флагами это всё конечно тоже так, но учесть все KF> флаги с их 2^n числом состояний, что типично много больше N -- KF> сложно. Hе понял. Почему N != 2^n ?

With best regards, Andrej Arnold. E-mail: snipped-for-privacy@aol.com

Reply to
Andrej Arnold

Привет, Alex !

03 Mar 06 , 00:42 Alex Mogilnikov писал к Igor Ulanov:

IU>> У меня оказывается еще старее - 3.4.3

AM> Фигня, некоторые до сих пор 2.96 используют. А вот четвертую ветку AM> любопытно попробовать, но, наверное, для ARM, т.к. avr я уже AM> практически не использую...

2.9_6_ - это вроде бы какой-то гнусный хак/патч от редхата, не совместимый ни с чем.

. С уважением, Hикита. icq:240059686, lj-user:nicka_startcev ... Выползень роду женского подло нарушил Обряд Чистописания

Reply to
Nickita A Startcev

Hello, Alex!

(03 Мар 06 00:42), Alex Mogilnikov писАл Igor Ulanov: AM> В исходном сишном коде я насчитал семь вызовов функций, а в AM> ассемблерном коде не вижу ни одного. Ты что, объявил все эти функции AM> инлайновыми? Как-то это не согласуется с оптимизации по размеру... Они объявлены так в библиотеке. Я ничего не менял. AM> И ассемблерный текст какой-то странный, не похож на то, что обычно AM> генерит gcc. Я смотрю текст в файле для отладчика с расширением lss, мне так удобнее, так как там присутствует и Сишный текст. У тебя библиотека явно отличается от моей. Приду на работу скачаю все-таки что нибудь поновей. А пока изменил delay.h:

static __inline__ void _delay_loop_1(uint8_t __count) { __asm__ volatile ( "1: dec %0" "\n\t" "brne 1b" : "=r" (__count) : "0" (__count) ); }

static __inline__ void _delay_loop_2(uint16_t __count) { __asm__ volatile ( "1: sbiw %0,1" "\n\t" "brne 1b" : "=w" (__count) : "0" (__count) ); }

static __inline__ void _delay_loop_3(uint16_t __count_w, uint8_t __count) {

__asm__ volatile ( "1:" "\n\t" "2:" "\n\t" "sbiw %0,1" "\n\t" "brne 2b" "\n\t" "dec %1" "\n\t" "brne 1b" "\n\t" :: "w" (__count_w), "r" (__count) ); }

static __inline__ void _delay_us(double __us) { double __tmp=(F_CPU/3e6)*__us;

if (__tmp<1.0) _delay_loop_1(1); else if (__tmp<256) _delay_loop_1((uint8_t)__tmp); else if (__tmp<65536) _delay_loop_2((uint16_t)(F_CPU/4e6)*__us); else _delay_loop_2(0); }

static __inline__ void _delay_ms(double __ms) { double __tmp =(F_CPU/3e3)*__ms;

if (__tmp<1.0) _delay_loop_1(1); else if (__tmp<256) _delay_loop_1((uint8_t)__tmp); else { __tmp=(F_CPU/4e3)*__ms; if (__tmp<65536) _delay_loop_2((uint16_t)__tmp); else if (__tmp<16777216) _delay_loop_3((uint16_t)(__tmp-(__tmp/65536)),(uint8_t)(__tmp/65536)); else _delay_loop_3(0,0); } }

Теперь хоть нет идиотского ограничения в _delay_us(), с которым я имел проблему пока не посмотрел что делает функция в исходнике.

AM> Сделал ты все правильно, но застрахован не будешь. :) Hо надеюсь SVN избавит от лихорадочных попыток вспомнить, какие изменения вносились когда решал ту или иную задачу. Сейчас пожалуй это основная проблема. AM> Во-первых, свои ошибки вообще трудно заметить. Да, к великому сожалению это так. Практически совершено не заметны "опечатки", так как когда смотришь исходник в большей степени "читаешь" не его, а свои воспоминания о решениях. Если бы можно было бы выключать отдельные участки памяти было бы намного проще:)

По-поводу SVN. В русском описании есть предупреждение, что хранилище нельзя располагать на "сетевой шаре" - это так? Мне очень удобно было бы расположить свое хранилище на сервере. Или под "сетевой шарой" понимается что-то другое?

With best regards, Igor. Time: 14:22 Date: 04 Мар 06

Reply to
Igor Ulanov

Привет Nickita!

03 Mar 06 20:59, Nickita A Startcev писал Alex Mogilnikov:

NS> 2.9_6_ - это вроде бы какой-то гнусный хак/патч от редхата, не NS> совместимый ни с чем.

Возможно. Hе помню точно, чем там вторая ветка кончилась. 2.95 наверное?

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Собака - вдруг человека...

Reply to
Alex Mogilnikov

Потому что состояний может быть меньше, чем 2^n флагов. Например, какой-то флаг в каком-то состоянии не имеет смысла. А наоборот быть не может.

Reply to
Kirill Frolov

delay() вообще имеет смысл или только для очень коротких временных интервалов, или в случае, когда вся программа посчитана по тактам, чего на C сделать невозможно.

Reply to
Kirill Frolov

Ага. В дебиане именно он, без всяких редхатов.

Reply to
Kirill Frolov

Привет Igor!

04 Mar 06 14:22, Igor Ulanov писал Alex Mogilnikov:

AM>> И ассемблерный текст какой-то странный, не похож на то, что AM>> обычно генерит gcc. IU> Я смотрю текст в файле для отладчика с расширением lss, мне так IU> удобнее, так как там присутствует и Сишный текст.

Тогда тебе еще удобней будет смотреть ассемблерный листинг. В нем, по крайней мере, ассемблерный текст в неизменном виде. А в твоем lss, похоже, текст получен дизассемблированием из машинных кодов. Hу не пишет gcc "brne .-4", он для переходов метки ставит. :)

IU> У тебя библиотека явно отличается от моей.

А я и не использовал никакую библиотеку. Речь шла только о кодогенерации. Я просто скопировал твой пример, добавив недостающие декларации. Вот исходный текст (надо было сразу его привести, я забыл):

========== test.c =========== #include <inttypes.h> /* только ради uint8_t */

void cli(void); void sei(void); void microlan_port_down(void); void microlan_port_up(void); void _delay_us(unsigned int); void _delay_ms(float);

extern uint8_t PINB;

uint8_t Read_byte_microlan(void) { // функция чтения байта с линиии microlan uint8_t i, byte;

byte = 0; for(i = 0; i < 8; i++) { byte = byte >> 1; cli(); microlan_port_down(); _delay_us(4); microlan_port_up(); _delay_us(13); if(PINB & 0x01) byte += 0x80; sei(); _delay_ms(0.06); } return (byte); } =============================

IU> По-поводу SVN. В русском описании есть предупреждение, что хранилище IU> нельзя располагать на "сетевой шаре" - это так?

Hе знаю, я использую CVS, и его репозиторий только через сеть и доступен. Тут многие svn используют, я думаю, подскажут тебе.

Всего наилучшего, [Team PCAD 2000] Алексей М. ... Посетители должны общаться по сети.

Reply to
Alex Mogilnikov

Hi Kirill !

Совсем недавно 04 Mar 06 15:36, Kirill Frolov писал к Andrej Arnold:

KF> Потому что состояний может быть меньше, чем 2^n флагов. Hапример, KF> какой-то флаг в каком-то состоянии не имеет смысла. А наоборот быть не KF> может. "Hе может быть" и "Hе имеет смысла" - это две большие разницы. Если твоя эхотажная программа не знает что делать в ситуациях, которые "не имеют смысла"

- это ненадежное программирование.

WBRgrds Ruslan

Reply to
Ruslan Mohniuc

Kirill, ты ещё здесь сидишь?

Суббота Март 04 2006 15:36, Kirill Frolov wrote to Andrej Arnold:

Это правильно, но будет ли удобно с ними работать? Простенький пример, анализ состояния дверей автомобиля. Вместо простенького описания вида "это флажок закрытия передней левой двери, а это флажок закрытия передней правой..." будет страшненький список состояний вида "левая передняя дверь открыта, причём правая передняя закрыта, левая задняя тоже закрыта, и правая задняя тоже закрыта..." По-моему такая "экономия числа состояний" сродни созданию переменной, в которой при одних условиях размещается таймер режимов стеклоочистителя, а в других - код с "охранки". Экономия в один жалкий байт и куча возможностей для нелепых ошибок в программе...

Георгий

Reply to
George Shepelev

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

Пример: допустим, есть файл, который может быть открыт (для виндовса) в текстовом или двоичном режиме. И два флага: признак того, что файл открыт, и режим в котором открыт файл. Очевидно, что в случае, когда файл не открыт флаг указывающий на режим смысла не имеет.

Reply to
Kirill Frolov

Привет, Alex !

04 Mar 06 , 15:18 Alex Mogilnikov писал к Nickita A Startcev:

NS>> 2.9_6_ - это вроде бы какой-то гнусный хак/патч от редхата, не NS>> совместимый ни с чем.

AM> Возможно. Hе помню точно, чем там вторая ветка кончилась. 2.95 AM> наверное?

Именно.

. С уважением, Hикита. icq:240059686, lj-user:nicka_startcev ... Пристают к [За/Под]ставе гости

Reply to
Nickita A Startcev

Я ж писал: можно разбить на несколько автоматов. Потому как хоть и можно всё описывать исключительно одним состоянием, это ненаглядно и число их (они перемножаются) очень велико. В данном случае целесообразно для каждой двери иметь своё состояние. Но где-то наоборот.

А в описанном случае с файлом лучше иметь состояния. Потому как очень легко наступить на грабли при попытке поработать с закрытым файлом.

Reply to
Kirill Frolov

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.