реклама на сайте
подробности

 
 
> Отладка в KEIL. Как вычислить, откуда в переменной появляются данные?
zheka
сообщение Aug 13 2013, 02:47
Сообщение #1


Гуру
******

Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164



Есть функция
Код
OW_ReceiveByte()
{   unsigned char count, data;
count = 8;
  do
   {
    data >>= 1;
    if(OW_ReadBit()) data |= 0x80;
   }
  while(--count);

  return data;
}


каким-то непостижимым образом в data изначально появляются данные. Каждый раз одинаковые. Даже если ничего не писать в data, а по выходу из функции прочитать то, что она возвращает.

Как вычислить с помощью отладчика?
Контроллер - STM32F103VGT6

Сообщение отредактировал zheka - Aug 13 2013, 02:48
Go to the top of the page
 
+Quote Post
2 страниц V   1 2 >  
Start new topic
Ответов (1 - 18)
VAI
сообщение Aug 13 2013, 03:52
Сообщение #2


Профессионал
*****

Группа: Модераторы
Сообщений: 1 120
Регистрация: 17-06-04
Пользователь №: 37



data у Вас - локальная переменная, то место ей выделяется в стеке, а там какой-нибудь мусор - вот и результат.
Объявите
Код
static unsigned char data;

и data будет инициализирована нулём.
Вам надо почитать учебники по С.


--------------------
Если зайца бить, его можно и спички научить зажигать
Сколько дурака не бей - умнее не будет. Зато опытнее
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Aug 13 2013, 04:12
Сообщение #3


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



Вроде как по стандарту локальные переменные должны инициализироваться нулём в C. Но если у вас такая беда, то можете явно проинициализировать. Выносить в глобальные переменные смысла особого нет - читается один байт и при возврате из функции будет происходить копирование этого байта, то есть у вас всё правильно написано.
Go to the top of the page
 
+Quote Post
toweroff
сообщение Aug 13 2013, 04:31
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



А если непосредственно по вопросу темы, то в окне "Breakpoints" в поле "Expression" необходимо ввести что-то типа "data==0"
При этом data должна быть глобальной
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Aug 13 2013, 04:42
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



А если совсем по теме то КЕИЛ может делать такие чудеса с переменными которые не глобальные, что диву даешься. Всегда использовал отладку печатью в порт. Но тут уговорили жетагом попробовать, типа как удобно, сначала я думал что сошел с ума и ничего не понимаю в программировании, потом нашел на сайте кейла ремарку. У него есть ограничение на отображения переменных и иногда он показывает полную чушь.

Типа в окне переменная равна 5, а условие если переменная равна нулю проходит верно... это очень сбивает
Go to the top of the page
 
+Quote Post
toweroff
сообщение Aug 13 2013, 04:49
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



Цитата(Golikov A. @ Aug 13 2013, 08:42) *
Типа в окне переменная равна 5, а условие если переменная равна нулю проходит верно... это очень сбивает

очень многое зависит и от уровня оптимизации, и от отладчика
я подобными бряками не пользовался, просто указал на их наличие в IDE, а вот что касаемо неверного отображения значений переменных в отладчике - спотыкался не раз... массив данных отображается неверно, а если посмотреть область памяти по адресу массива - там все четко
Go to the top of the page
 
+Quote Post
zheka
сообщение Aug 13 2013, 05:25
Сообщение #7


Гуру
******

Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164



Цитата
static unsigned char data;

Код
Но если у вас такая беда, то можете явно проинициализировать.

Спасибо за советы, но я немножко не об этом хотел узнать. Проблема то решена принудительным обнулением.
Но - по логике вещей в data ничего не должно писаться без ведома программы, так собственно и происходит с остальными пермененными.

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

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

Так что смысл вопроса, смысл темы объяснить на пальцах как решить эту проблему KEILовским отладчиком.
Цитата
Всегда использовал отладку печатью в порт.

Мой первый проект еще на AVR был с дисплеем, я привык отлаживать, выводя нужную информацию на экран, так что к своему стыду, отладчиком пользоваться не умею. Копнул недавно на теу отладки в KEIL, добавил в окно мониторинга пару переменных и был разочарован - чтобы узнать их значение, программу нужно останавливать. Куда удобнее выводить на экран.

А вот ловлю обращений к памяти выводом на экран не организуешь.

Цитата
"Breakpoints" в поле "Expression" необходимо ввести что-то типа "data==0"
При этом data должна быть глобальной

Если делать переменную глобальной, проблема исчезает, так что смысл в отладке теряется. Зато появляется ощущени нерациональности программы.

Как сделать две вещи - определить адрес в памяти, выделенный под data и как определить "клиента" который на этот адрес покушается?

Цитата
массив данных отображается неверно, а если посмотреть область памяти по адресу массива - там все четко

Никогда похожих проблем не было с выводом на экран или запись в порт. Как-то расхотелось пользоваться житагом.
Go to the top of the page
 
+Quote Post
richie
сообщение Aug 13 2013, 05:27
Сообщение #8


Частый гость
**

Группа: Свой
Сообщений: 147
Регистрация: 5-07-04
Из: Обнинск
Пользователь №: 261



zheka, возьмите в привычку: объявил переменную, проинициализируй её.
Даже для локальных переменных.
Для любых компиляторов.

В проектах, где "поджимает" объем кода, отключаю инициализацию глобальных переменных.
Один фиг, аналогичные по функционалу функции в моём коде есть, которые и использую при запуске.

P.S. Имя "data" лучше изменить на хотя бы "Data", а лучше на что-то подлиннее, более содержательное, например "readData".
Go to the top of the page
 
+Quote Post
zheka
сообщение Aug 13 2013, 05:36
Сообщение #9


Гуру
******

Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164



Цитата
zheka, возьмите в привычку: объявил переменную, проинициализируй её.

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

То есть вы хотите сказать, что при объявлении переменной программа не заботится о том, чтобы она равнялась нулю, а на практике она равна нулю только потому, что ко времени выделения памяти под переменную в ней находятся нули чисто физически, потому что память обнуляется при старте?
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Aug 13 2013, 05:56
Сообщение #10


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



Цитата
При изучении чужих программу меня сложилось ощущение, что принудительная инициализация - это паранойя.

Так и есть.

Название data для переменной тоже нормальное, так как область видимости очень короткая.

Цитата
потому, что ко времени выделения памяти под переменную в ней находятся нули чисто физически, потому что память обнуляется при старте?

Ничё там не обнуляется при старте. При старте там мусор, а за обнуление отвечает специальный код, который чистит секцию init. richie пишет о том, что он всё принудительно инитит, поэтому отключил очистку секции init.
Go to the top of the page
 
+Quote Post
Raven
сообщение Aug 13 2013, 05:59
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 491
Регистрация: 16-01-05
Из: Санкт-Петербург
Пользователь №: 1 987



Цитата(zheka @ Aug 13 2013, 09:36) *
То есть вы хотите сказать, что при объявлении переменной программа не заботится о том, чтобы она равнялась нулю, а на практике она равна нулю только потому, что ко времени выделения памяти под переменную в ней находятся нули чисто физически, потому что память обнуляется при старте?

А почему компилятор должен эту переменную инициализировать, собственно? По коду она просто задекларирована, а потом сразу начинает использоваться, без инициализации (!!!!). Все законно. Что к моменту использования было, то и получили. Из стека. А вот с count все как надо с самого начала.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Aug 13 2013, 05:59
Сообщение #12


Гуру
******

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



QUOTE (andrewlekar @ Aug 13 2013, 06:12) *
Вроде как по стандарту локальные переменные должны инициализироваться нулём в C.
Перечитайте стандарт. Только глобальные и статические переменные.
QUOTE (zheka @ Aug 13 2013, 07:25) *
Проблема то решена принудительным обнулением.
А проблемы не было. У вас 8-битовая переменная и вы 8 раз в нее вдвигаете биты. Все ваши обнуленные биты "выталкиваются" из переменной во время исполнения функции. Поэтому начальное значение data на результат не влияет.
QUOTE (zheka @ Aug 13 2013, 07:25) *
Но - по логике вещей в data ничего не должно писаться без ведома программы, так собственно и происходит с остальными пермененными.
А в нее ничего специально и не пишется. Просто двоичная система не имеет состояния "ничего не записано". Поэтому изначально там случайный набор битов.
QUOTE (zheka @ Aug 13 2013, 07:25) *
Как выяснилось, массив у меня был без указания размера, а по сему пользовался "ничейной" областью памяти. И когда программа хотела в эту область записать еще что-то, ей это удавалось.
Наоборот. Это вы писали за границы своего массива нулевой длины и портили другие переменные, а потом пытались эти переменные считать как содержимое своего массива.
QUOTE (zheka @ Aug 13 2013, 07:25) *
Так вот у меня опасения, что причина проблем с переменной data схожая, боюсь что словлю глюк где-нибьудь еще и понять его причину будет сложно.
С переменной data проблем нет. И чудес не бывает и нет. Проблема в том, что вы пытаетесь пользоваться инструментом (языком C) не изучив его. Вы же не пытаетесь методом "тыка" использовать лекарства из домашней аптечки - здесь вы имеете такой же летальный для вашей программы результат.
QUOTE (zheka @ Aug 13 2013, 07:25) *
Копнул недавно на теу отладки в KEIL, добавил в окно мониторинга пару переменных и был разочарован - чтобы узнать их значение, программу нужно останавливать. Куда удобнее выводить на экран.

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

QUOTE (zheka @ Aug 13 2013, 07:25) *
Как сделать две вещи - определить адрес в памяти, выделенный под data и как определить "клиента" который на этот адрес покушается?

1)прочитать описание языка и из него узнать, где размещаются локальные переменные
2)посмотреть дизассемблированный код функции и узнать смещение переменной в стековом кадре или имя регистра (компилятор имеет право расположить ее и в регистре).
3) на шаге 1 понять, что никто никуда не покушается и ничего не портит.

QUOTE (zheka @ Aug 13 2013, 07:25) *
Никогда похожих проблем не было с выводом на экран или запись в порт. Как-то расхотелось пользоваться житагом.
"Ну дык, еб тыть" - сказали суровые русские мужики и пошли валить лес двуручными пилами.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
zheka
сообщение Aug 13 2013, 07:50
Сообщение #13


Гуру
******

Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164



Цитата
А проблемы не было. У вас 8-битовая переменная и вы 8 раз в нее вдвигаете биты. Все ваши обнуленные биты "выталкиваются" из переменной во время исполнения функции. Поэтому начальное значение data на результат не влияет.

хм... об этом я как-то не подумал.
ПРосто когда методом тыка разбирал функцию по косточкам, я пытался понять откуда там берутся лишние биты.
Когда увидел, что какой-то мусор присутствует изначально, и что программа работает после принудительного обнуления data, радости после трехдневных мук не было предела, я свалил все на изначальный мусор.

А вообще, проблема гадкая, напоминает ситуацию, когда в какой-то функции уберешь одну фигурную скобку, то компилятор выдает ошибку в километре от этого места, приводя в недоумение. Боюсь что и здесь что-то подобное, болит голова, а причина где-то в пятке.

Сообщение отредактировал zheka - Aug 13 2013, 07:51
Go to the top of the page
 
+Quote Post
редактор
сообщение Aug 13 2013, 07:52
Сообщение #14


Местный
***

Группа: Участник
Сообщений: 356
Регистрация: 9-06-07
Пользователь №: 28 315



При входе в отладчик в кейле в менюшке (View кажется) есть пункт периодического обновления данных.
Если установить ему галку в процессе выполнения данные о переменных обновляются примерно раз в секунду.


--------------------
Хорошую систему делают из стандартных блоков нестандартно мыслящие инженеры.
Go to the top of the page
 
+Quote Post
zheka
сообщение Aug 13 2013, 12:09
Сообщение #15


Гуру
******

Группа: Участник
Сообщений: 2 072
Регистрация: 14-01-06
Пользователь №: 13 164



Цитата(редактор @ Aug 13 2013, 11:52) *
При входе в отладчик в кейле в менюшке (View кажется) есть пункт периодического обновления данных.
Если установить ему галку в процессе выполнения данные о переменных обновляются примерно раз в секунду.


А ведь правда)) Спасибо.
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Aug 13 2013, 14:25
Сообщение #16


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



а еще

Код
int data
int * data_adr = &data;


всегда считал что все переменные до инициализации содержат мусор, не знал про статик и глобальные. А кто их нулит? Ведь есть системы где память после загрузки не 0, процы на плисах к примеру, 9 Кбайтные блоки памяти у них не нулятся при старте, даже если просить...

а еще 16 битные переменные в 8 битных контроллерах умеют во время прерывания на половину изменятся, не говорят про 32 и 64 битные переменные... Что же вы теперь программу будете всю отладчиком шерстить? Лучше уже писать безопасный код ИМХО.

Доказательство лучше проверки...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Aug 13 2013, 20:53
Сообщение #17


Гуру
******

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



QUOTE (Golikov A. @ Aug 13 2013, 16:25) *
всегда считал что все переменные до инициализации содержат мусор, не знал про статик и глобальные. А кто их нулит?
Обычно это специальный так называемый стартап код, который выполняется перед запуском main(). В стандарте сказано просто что-то вроде "переменные обнуляются". Чем и как - вроде бы не оговаривается.

QUOTE (Golikov A. @ Aug 13 2013, 16:25) *
Что же вы теперь программу будете всю отладчиком шерстить? Лучше уже писать безопасный код ИМХО.
Если бы все были этакими сферическими программистами в вакууме, способными писать код сразу без ошибок... Часто проход по шагам небольшого кусочка кода, исполняющегося не так, как ожидал автор, позволяет за один проход найти ошибку. Все остальные методы отладки, включая медитацию над исходником, требуют гораздо больше времени.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
toweroff
сообщение Aug 13 2013, 21:19
Сообщение #18


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



Что есть startup?
кусок кода, который, обычно:
1. Содержит вектора прерываний
2. Содержит кусок кода, который выделит и укажет стек(и)
3. Отправит в __main

Что есть __main? это библиотека, при компиляции собранная с заданными параметрами:
1. Обнулить область ZEROINIT
2. Перенести код, если указан, в нужную область
3. Передать управление в точку main()

Сделать тоже самое просто в C можно спокойно и не напряжно. Без всяких библиотек. Что мешает сделать код инициализации переменных самому? Что позволяет надеяться на абсолютно рандомное содержимое области стека?
По факту топика - реализация сдвига на C (сколько ни сталкивался) всегда записывала 0 в освобожденный разряд. Это не циклический сдвиг на ASM
Про состояние локальных переменных уже все сказали
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Aug 14 2013, 03:43
Сообщение #19


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



Цитата(Сергей Борщ @ Aug 14 2013, 00:53) *
Обычно это специальный так называемый стартап код, который выполняется перед запуском main(). В стандарте сказано просто что-то вроде "переменные обнуляются". Чем и как - вроде бы не оговаривается.

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



Ок, будем знать как говориться... Но я на всякий случай важные переменные все равно буду в начале инициализировать. Потери от этого если и есть, то они мизерные, зато как то внутри спокойнее....

Я не про отладку в целом, я про фразу человека что он сделал массив без размера, фактически указатель, а потом загадив им память начал тыкать отладчиком во все функции и смотреть как локальные переменные объявляются, и не приводит ли это к чему... так проверить все я уверен нельзя. Потому считаю что лучше объявить переменную явно если от ее значения сразу что-то зависит, либо писать код учитывая что в начале она имеет любое значение.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 19:25
Рейтинг@Mail.ru


Страница сгенерированна за 0.01555 секунд с 7
ELECTRONIX ©2004-2016