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

 
 
> Неожиданный результат, Прочитать два байта
alux
сообщение Jan 19 2008, 14:37
Сообщение #1


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Долго не мог выявить, почему цифровой датчик давления выдает неверный результат.
Код
//Первый случай;
resultat = ((unsigned int)i2c_read(ACK)<<8) | i2c_read(ACK);

//Второй случай:
HiTemp=i2c_read(ACK);        
LowTemp=i2c_read(ACK);
resultat = ((unsigned int)HiTemp<<8) | LowTemp;

Во втором случае дает другой (правильный) результат. Почему?
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Сергей Борщ
сообщение Jan 19 2008, 14:45
Сообщение #2


Гуру
******

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



Цитата(alux @ Jan 19 2008, 16:37) *
Во втором случае дает другой (правильный) результат. Почему?
Потому что стандарт языка С не определяет порядок вычисления подвыражений.
Какой из i2c_read() будет вызван первым зависит в общем случае от положения звезд на небе. Ваша функция обладает побочными эффектами, поэтому вызывать ее дважды в одном выражении не рекомендуется во избежание таких неожиданностей.


--------------------
На любой вопрос даю любой ответ
"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
Aesthete Animus
сообщение Jan 20 2008, 12:17
Сообщение #3


Местный
***

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



Цитата(Сергей Борщ @ Jan 19 2008, 17:45) *
Потому что стандарт языка С не определяет порядок вычисления подвыражений.

Что значит, стандарт не определяет? Вот строчка из "K&R C": "Все бинарные операции и условная операция (прим. Перевод.: условная операция группируется справа налево; это изменение внесено в язык в 1978 г.) группируются слева направо"

Это следут проверить таким образом:
Код
resultat = ((HiTemp = (unsigned int)i2c_read(ACK))<<8) | (LowTemp = i2c_read(ACK));

printf("High byte 0x%02X\n", HiTemp);
printf("Low byte 0x%02X\n", LowTemp);
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 20 2008, 18:59
Сообщение #4


Гуру
******

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



Цитата(Aesthete Animus @ Jan 20 2008, 14:17) *
Вот строчка из "K&R C": "Все бинарные операции и условная операция (прим. Перевод.: условная операция группируется справа налево; это изменение внесено в язык в 1978 г.) группируются слева направо"
Если под бинарными понимаются && и || - определен. Для остальных (кроме ?: и оператора "запятая") - нет. Вот цитата из стандарта языка (INTERNATIONAL STANDARD ISO/IEC 9899, Programming languages — C, Second edition 1999-12-01):
Цитата
6.5 Expressions
....
3 The grouping of operators and operands is indicated by the syntax. Except as specified later (for the function-call (), &&, ||, ?:, and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified.
Это дает гораздо больше свободы оптимизатору.


Цитата(alux @ Jan 20 2008, 17:01) *
Вот что выдал листинг:
Мне пришло в голову, что во избежание подобных недоразумений функцию надо бы объявить как volatile. В этом случае:
1) Компилятор был бы обязан вызвать ее дважды.
2) IAR выдал бы предупреждение о неопределенности при использовании более одной volatile в выражении. GCC такое предупреждение не выдает, это ему минус. Хотя когда в IAR появилась эта проверка - многих предупреждение ставило в тупик. Вот, видимо, наглядный пример, когда это предупреждение обосновано.


--------------------
На любой вопрос даю любой ответ
"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
singlskv
сообщение Jan 20 2008, 22:07
Сообщение #5


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(Сергей Борщ @ Jan 20 2008, 21:59) *
Мне пришло в голову, что во избежание подобных недоразумений функцию надо бы объявить как volatile. В этом случае:
1) Компилятор был бы обязан вызвать ее дважды.
Даже без volatile компилятор обязан был вызвать эту функцию дважды, т.к. внутри
этой функции есть работа с volatile переменными, например с регистрами TWI...

P.S. Нда... , чего-то у IAR совсем плохо c volatile..., уже 2 баги за последние пару дней...
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Jan 21 2008, 07:39
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823



Цитата(singlskv @ Jan 21 2008, 02:07) *
Даже без volatile компилятор обязан был вызвать эту функцию дважды, т.к. внутри
этой функции есть работа с volatile переменными, например с регистрами TWI...

P.S. Нда... , чего-то у IAR совсем плохо c volatile..., уже 2 баги за последние пару дней...


Ничего он не обязан.
Кто писал программу - Вы или компилятор? smile.gif
Все свойства функции - это типы параметров и адрес вызова, а требовать от компилятора анализа свойств используемых переменных внутри функции - эта попытка взвалить на него исправление Ваших ошибок.


--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
singlskv
сообщение Jan 21 2008, 20:54
Сообщение #7


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(Dog Pawlowa @ Jan 21 2008, 10:39) *
Ничего он не обязан.
Кто писал программу - Вы или компилятор? smile.gif
Все свойства функции - это типы параметров и адрес вызова, а требовать от компилятора анализа свойств используемых переменных внутри функции - эта попытка взвалить на него исправление Ваших ошибок.
Атлична, раскажите мне пожалуйста, исходя из каких правил описанных в стандарте С
компилятор имеет право обработать эти две ситуации по разному:
Код
int NegPort()
{
  PORTB~=0xFF;
  return 1;
}

.......
  a = NegPort() + NegPort();

и
Код
a = NegPort();
a+=NegPort();


по Вашей логике в первом случае он имеет право вызвать NegPort() один раз а во втором
обязян вызвать 2 раза...
и почему во втором случае он не вызовет так же один раз ?

О порядке вызова функций при сложении речи не идет...

P.S. Пример конечно сильно упрощен, но смысл я надеюсь понятен...

P.P.S А так же в догонку очень хотелось бы понять, имеет ли право на жизнь
следующая запись в языке С:
Z = X * K1 * rand() + Y * K2 * rand();
или я обязан разделить ее на 2 подвыражения для того чтобы не получить одинаковый
результат на выходе rand().... ???
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 21 2008, 21:10
Сообщение #8


Гуру
******

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



Цитата(singlskv @ Jan 21 2008, 22:54) *
по Вашей логике в первом случае он имеет право вызвать NegPort() один раз а во втором обязян вызвать 2 раза... и почему во втором случае он не вызовет так же один раз ?
Видимо потому, что между вызовами во втором случае стоит ";", т.е. sequence point, на момент которой все побочные эффекты должны выполниться. Побочным эффектом в данном случае является запись в PORTB. Если я все правильно понимаю.


--------------------
На любой вопрос даю любой ответ
"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
singlskv
сообщение Jan 21 2008, 21:16
Сообщение #9


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(Сергей Борщ @ Jan 22 2008, 00:10) *
Побочным эффектом в данном случае является запись в PORTB. Если я все правильно понимаю.

конечно, и функция уже должна наследовать признак "volatile", те sequence point должны
быть при каждом вызове этой функции
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 21 2008, 23:13
Сообщение #10


Гуру
******

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



Цитата(singlskv @ Jan 21 2008, 23:16) *
конечно, и функция уже должна наследовать признак "volatile"
Кому должна? Ведь тело функции может находиться и в другой единице компиляции. Откуда в таком случае компилятор узнает, что вы в ней обращаетесь к volatille-объектам? Я полагаю, что для получения правильного поведения функция должна быть описана как int NegPort() voltile {}. "И сразу польется вода" © Тот самый Мюнхгаузен.


--------------------
На любой вопрос даю любой ответ
"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
singlskv
сообщение Jan 22 2008, 08:50
Сообщение #11


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(Сергей Борщ @ Jan 22 2008, 02:13) *
Ведь тело функции может находиться и в другой единице компиляции. Откуда в таком случае компилятор узнает, что вы в ней обращаетесь к volatille-объектам? Я полагаю, что для получения правильного поведения функция должна быть описана как int NegPort() voltile {}.

Хорошо, есть функция rand() которая определена в другой единице компиляции,
в стандартной библиотеке.
Определена она так int rand(void) , т.е. без всяких volatile.

Вопрос:
Могу ли я написать у себя в программе
А = rand() + rand(); ?
или компилятор может вызвать rand только один раз ?
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- alux   Неожиданный результат   Jan 19 2008, 14:37
|- - alux   Я поражен меткости и, главное, оперативности Ваших...   Jan 19 2008, 14:53
|- - Aesthete Animus   Цитата(Сергей Борщ @ Jan 20 2008, 21:59) ...   Jan 20 2008, 19:43
||- - Сергей Борщ   Цитата(Aesthete Animus @ Jan 20 2008, 21...   Jan 20 2008, 21:34
|- - Сергей Борщ   Цитата(singlskv @ Jan 22 2008, 10:50) Воп...   Jan 22 2008, 11:57
|- - singlskv   Цитата(Сергей Борщ @ Jan 22 2008, 14:57) ...   Jan 22 2008, 12:44
|- - alux   Цитата(singlskv @ Jan 22 2008, 16:44) Авт...   Jan 22 2008, 13:31
|- - singlskv   Цитата(alux @ Jan 22 2008, 16:31) Прошу п...   Jan 22 2008, 17:53
|- - alux   Код 49 Accumulator = ((unsigned int...   Jan 22 2008, 19:47
|- - ReAl   Цитата(alux @ Jan 22 2008, 15:31) Кстати,...   Jan 22 2008, 21:17
|- - alux   Цитата(ReAl @ Jan 23 2008, 01:17) У IAR-а...   Jan 23 2008, 07:13
|- - ReAl   Я немного цитаты перетасую Цитата(alux @ Jan...   Jan 23 2008, 14:49
|- - alux   Цитата(ReAl @ Jan 23 2008, 18:49) в преды...   Jan 23 2008, 15:10
|- - Сергей Борщ   Цитата(alux @ Jan 23 2008, 17:10) ReAl ог...   Jan 23 2008, 15:30
|- - ReAl   Цитата(Сергей Борщ @ Jan 23 2008, 17:30) ...   Jan 24 2008, 08:04
- - Baser   Цитата(alux @ Jan 19 2008, 16:37) Долго н...   Jan 19 2008, 15:44
- - rezident   Я не такой большой специалист в Си и могу ошибатьс...   Jan 20 2008, 12:23
- - alux   Цитата(rezident @ Jan 20 2008, 16:23) ......   Jan 20 2008, 15:01


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

 


RSS Текстовая версия Сейчас: 27th July 2025 - 08:39
Рейтинг@Mail.ru


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