|
Как бороться с внезапной ассемблерной вставкой? |
|
|
|
Jan 8 2012, 16:35
|
Участник

Группа: Участник
Сообщений: 44
Регистрация: 30-04-10
Пользователь №: 56 995

|
Есть программа, написанная на Си, рабочая. Для отладки программы использовал 16х2-дисплей. Т.к. программа написана, необходимо убрать этот дисплей. Чтобы это можно было сделать быстро, везде, где он используется, писал так: Код if (LCD_YES) { lcd_puts("Не важно что") } и в самом начале листинга соотвественно Код define LCD_YES 1 где можно быстро включать-выключать дисплей. Суть вот в чем - ни разу я его не отключал (да и зачем было?), программа написана, пришло время поставить вместо единицы нолик, что и было сделано. И тут программа перестала работать. Код int main(void) { Init(); // инициализация портов, таймеров и др. RecipientComplete = 0; // обнуляем флаг приемки данных PORTC &= ~(1<<SIM900D_ON); // Включаем SIM900D - сажаем на "0" выход для открытия транзистора PORTC |= (1<<PWR_KEY); PORTC &= ~(1<<PWR_KEY); while(1) { nop(); if (RecipientComplete == 1) // Если пришла посылка от SIM900D { ReceiveAnalysis(rx_buffer); // Анализируем } nop(); } } Шерстя по ассемблерному коду, увидел, что перед while(1) появился такой код: Код 945: PORTC &= ~(1<<PWR_KEY); +0000059C: 98AF CBI 0x15,7 Clear bit in I/O register 952: nop(); +0000059D: 0000 NOP No operation 953: nop(); +0000059E: 0000 NOP No operation 958: nop(); +0000059F: 0000 NOP No operation +000005A0: CFFC RJMP PC-0x0003 Relative jump 958: nop(); самого while() нету, да собственно и не нужен, т.к. RJMP PC-0x0003 зацикливает программу на месте между nop'ами. Почему такое происходит, и как от этого избавиться?
|
|
|
|
|
Jan 8 2012, 18:06
|
Участник

Группа: Участник
Сообщений: 44
Регистрация: 30-04-10
Пользователь №: 56 995

|
Гениально  Всем спасибо, помогло.
|
|
|
|
|
Jan 9 2012, 10:37
|
Знающий
   
Группа: Участник
Сообщений: 783
Регистрация: 22-11-08
Пользователь №: 41 858

|
Цитата(Apik @ Jan 8 2012, 20:35)  Есть программа, написанная на Си, рабочая. Для отладки программы использовал 16х2-дисплей. Т.к. программа написана, необходимо убрать этот дисплей. Чтобы это можно было сделать быстро, везде, где он используется, писал так: Код if (LCD_YES) { lcd_puts("Не важно что") } Чтобы это сделать быстро - есть условная компиляция Код #ifdef DEBUG #define DBG(s) lcd_puts(s) #else #define DBG(s) /* nothing */ #endif
int foo(int i) { if (i == 0) { DBG("foo: default value 10"); i = 10; } return i; } Отладочный вариант: Код sasa@sasa-laptop:~/tst$ cpp -DDEBUG tst.c # 1 "tst.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "tst.c"
int foo(int i) { if (i == 0) { lcd_puts("foo: default value 10"); i = 10; } return i; } Обычный без отладочных сообщений: Код sasa@sasa-laptop:~/tst$ cpp tst.c # 1 "tst.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "tst.c"
int foo(int i) { if (i == 0) { ; i = 10; } return i; } иначе LCD вам не нужен больше а код ненужный так и останется или его вручную выковыривать нужно. К тому же если завтра вам захочется отладку выводить через UART - достаточно будет поменять #define DBG(s) uart_puts(s) или любой другой вариант в зависимости от потребности.
Сообщение отредактировал sasamy - Jan 9 2012, 11:14
|
|
|
|
|
Jan 9 2012, 14:04
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Кстати, конструкция Код if(something) {...} во многих случаях нагляднее, чем Код #if something ... #endif Особенно, если подсветки синтаксиса нет.
|
|
|
|
|
Jan 9 2012, 14:28
|
Знающий
   
Группа: Участник
Сообщений: 783
Регистрация: 22-11-08
Пользователь №: 41 858

|
Цитата(Сергей Борщ @ Jan 9 2012, 16:58)  Да конечно. Неиспользуемый код ни один современный компилятор выкидывать не умеет. Dead code elimination - сказки для красноглазиков. А это вы видимо проигнорировали Цитата К тому же если завтра вам захочется отладку выводить через UART - достаточно будет поменять #define DBG(s) uart_puts(s) или любой другой вариант в зависимости от потребности. Например послезавтра считаем все неинициализированные переменные ошибкой и нужно локализовать их Код #define DBG(s) printf(s " at %s line %d\n", __FILE__, __LINE__ ) Впрочем вы можете продолжать учить красноглазить, а эти приемы в любом приличном учебнике по С описаны.
|
|
|
|
|
Jan 9 2012, 15:05
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (sasamy @ Jan 9 2012, 16:28)  А это вы видимо проигнорировали Я отвечал ровно на то, что процитировал. Вчитайтесь в свои собственные слова и учитесь отвечать за них. Правила хорошего стиля мне знакомы, заметьте, я ведь не писал что предложенный вами вариант плох или неправилен.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jan 9 2012, 15:14
|
Знающий
   
Группа: Участник
Сообщений: 783
Регистрация: 22-11-08
Пользователь №: 41 858

|
Цитата(Сергей Борщ @ Jan 9 2012, 19:05)  Я отвечал ровно на то, что процитировал. Вчитайтесь в свои собственные слова и учитесь отвечать за них. Вообще-то основной смысл был тут Цитата Чтобы это сделать быстро - есть условная компиляция а неточности - были, да. Вы таки рекомендуете делать так ? if (LCD) lcd_puts();
|
|
|
|
|
Jan 9 2012, 16:00
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(sasamy @ Jan 9 2012, 19:14)  а неточности - были, да. Вы таки рекомендуете делать так ? Угу, переходим от неточностей к необоснованным домыслам. Если отладочная часть заключается в одном вызове "печаталки", то, разумеется, лучше эту самую печаталку определить через дефайн. А вот если эта часть, например, требует каких-либо осмысленных действий, помимо одного вызова, то лучше оформить ее блоком, а проверку условия выполнить средствами языка, а не препроцессора: Код if(DEBUG) { // Объявляем локальные переменные
// Что-то извлекаем-считаем-выводим }
|
|
|
|
|
Jan 9 2012, 17:14
|
Знающий
   
Группа: Участник
Сообщений: 783
Регистрация: 22-11-08
Пользователь №: 41 858

|
Цитата(aaarrr @ Jan 9 2012, 20:00)  Угу, переходим от неточностей к необоснованным домыслам. Может быть мне конечно показалось  но какой смысл было акцентироваться на неточностях и плести про красноглазие ? хотя если говорить формально я написал достаточно точно - код после препроцессора до компилятора вообще не дойдет, тогда как с if он останется на усмотрение компилятора, но то что вручную выковыривать не надо - я согласен, соврал - например gcc всегда выкинет этот код сам и это помоему даже не отключить никак. Цитата Если отладочная часть заключается в одном вызове "печаталки", то разумеется лучше эту самую печаталку определить через дефайн. А вот если эта часть, например, требует каких-либо осмысленных действий помимо одного вызова, то лучше оформить ее блоком, а проверку условия выполнить средствами языка, а не препроцессора: Код if(DEBUG) { // Объявляем локальные переменные
// Что-то извлекаем-считаем-выводим } На любителя - чем это лучше #ifdef DEBUG { // Объявляем локальные переменные ...
|
|
|
|
|
Jan 9 2012, 18:00
|
Местный
  
Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123

|
Цитата(sasamy @ Jan 9 2012, 21:14)  На любителя - чем это лучше #ifdef DEBUG { // Объявляем локальные переменные ... Вариант с обычным if идеологически правильнее, чем с #ifdef потому, что прежде чем выкинуть недостижимый код, компилятор всё-таки проверит его корректность, в отличии от препроцессора. Автор темы задавал этот-же вопрос на другом форуме и там так-же возникла конфронтация #ifdef(DEBUG) VS if(DEBUG). Можете почитать мои доводы там.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|