Jump to content

    
Павел_Б

Вопрос по си

Recommended Posts

Здравствуйте.

Читаю чужой код и появился вопрос - что делает такая процедура:

___

A=0;
cnt=0;
do {
delay_ms(200);
cnt++;
}
while   ((A!=1) && (cnt!=200));

___

Я так понимаю что если программа дойдёт до этого места то будет ожидать пока А не станет равно 1 или не пройдёт 40 секунд.

Если А станет равно 1 то программа пойдёт дальше или если cnt станет равно 200 то программа тоже пойдёт дальше.

Правильно ли я понимаю этот кусок кода?

Спасибо!

 

Share this post


Link to post
Share on other sites

Судя по коду, А всегда тут 0, поэтому завершение цикла наступит только по второму условию

Скорее всего оптимизатор компилятора это увидит и сам автоматом выпилит условие A!=1, как бесплезное.

Но это при условии если A объявлена как локальная переменная.

Тоже самое касается cnt, она не должна быть доступна извне, например, из прерываний, иначе поведение кода неоднозначно.

 

Share this post


Link to post
Share on other sites

А - глобальная - то есть значение на 1 может измениться в другой подпрограмме по прерыванию.

cnt - локальная.

Как мне исправить код чтобы программа ждала пока А не станет 1 в другой подпрограмме или не пройдёт 40 секунд.

То есть программа должна пойти дальше в зависимости от одного из условий. 

Спасибо!

Edited by Павел_Б

Share this post


Link to post
Share on other sites
27 minutes ago, Павел_Б said:

Как мне исправить код чтобы программа ждала пока А не станет 1 в другой подпрограмме или не пройдёт 40 секунд.

ничего не надо исправлять, и так сойдет ;)

Share this post


Link to post
Share on other sites
49 минут назад, Павел_Б сказал:

А - глобальная

Какие еще у нее есть свойства? Присутствует ли в ее объявлении квалификатор volatile?

Share this post


Link to post
Share on other sites
12 minutes ago, Сергей Борщ said:

Какие еще у нее есть свойства? Присутствует ли в ее объявлении квалификатор volatile?

bit A;                  // - это глобальная битовая переменная

 

35 minutes ago, Forger said:

ничего не надо исправлять, и так сойдет ;)

Спасибо!

Share this post


Link to post
Share on other sites

Тогда я пас. Как известно, CV - компилятор с "языка, похожего на C". Если бы программа была написана на C, то без volatile компилятор, зная содержимое delay_ms() (т.е. зная, что A в ней не меняется), имел бы полное право выкинуть проверку (A!=1) из цикла, так как прямо перед циклом A = 0 и в цикле A не меняется.

Share this post


Link to post
Share on other sites

Раз уж у темы столь всеобъемлющее название, кину и я свой вопрос сюда.

Насколько идеологически правилен такого рода код:

volatile char A;
void Foo(const char *p);

int main(void){
  Foo(&A);
}

Компилятор выдает предупреждение о несоответствии типов параметра функции в описании и вызове. Погасить его можно применив явное приведение типа аргумента при передаче его в функцию: Foo((char*)(&A));

Что идеологически более правильно - забить на предупреждение компилятора, или явно привести тип аргумента, откинув тем самым из него volatile? Актуально для многих библиотечных функций, принимающих указатели. Например, memcpy, memcmp и т.п. Проблема возникает именно с указателями на volatile-переменные.

Случайно наткнулся и задумался, как бы это красиво и правильно решить.

Share this post


Link to post
Share on other sites
2 часа назад, Darth Vader сказал:

или явно привести тип аргумента, откинув тем самым из него volatile?

Если при использовании этой конкретной функции volatile ни на что не влияет - привести явно. Попробую объяснить: если вы передаете в, скажем, memcmp() массив volatile - переменных, и обращение к одним переменным не влияет на другие, т.е. допустимо обращение к элементам в любом порядке - то можно делать приведение типа. А вот если порядок влияет (скажем, вы передаете структуру какой-то периферии, где чтение регистра данных сбрасывает флаги и вам обязательно нужно прочитать сначала регистр флагов и только потом регистр данных) - то надо писать свою реализацию функции, приннимающую volatile-аргумент и обращающуюся к данным в нужном порядке.

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

2 часа назад, Darth Vader сказал:

и задумался, как бы это красиво и правильно решить

Переключить компилятор в режим C++ и переопределить функцию для volatile-аргумента. Пусть это явное приведение типа будет спрятано внутри переопределенной функции, а компилятор сам подставит вызов той или другой в зависимости от типа аргумента:

void Foo(char const *p);
inline void Foo(char const volatile *p) { Foo(const_cast<char const *>(p));

 

Share this post


Link to post
Share on other sites
2 часа назад, Darth Vader сказал:

Компилятор выдает предупреждение о несоответствии типов параметра функции в описании и вызове. Погасить его можно применив явное приведение типа аргумента при передаче его в функцию: Foo((char*)(&A));

Идеологически переменная объявлена как "может поменяться в любой момент сама", а аргумент как - "никто кроме функции её не поменяет". Естественно, исходя из этих объявлений компилятор и создает код.  Потому и предупреждает, что  возможно не зная о volatile функция вообще стала пустой.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.