Hello, Oleksandr!
AV>>> Что касается нормальности, то у каждого свои критерии, однако то, что AV>>> этот компилятор для AVR лучший из существующих - это точно. MR>> Тогда буду качать... OR> Качай, он пожалуй действительно самый лучший.
Скачал. Hо пока ещё не смотрел.
OR> Только предупреждаю, что он тоже в полном соответствии со стандартом С и OR> в полной противоположности с твоим мнением считает, что квалифицированную OR> как volatile переменную надо перезачитывать даже если в него писали OR> "только что": <...>
OR> p.s. поищи всё-таки нормальную книжку по C, если стандарт читать неохота,
Я бы лучше стандарт почитал (или его разбор/комментарии к нему), потому что в книжках бывает не написано или написано не то. (Примечание, добавленное после написания всего письма: стандарт всё-таки совершенно невменяемо написан. Hадо что-нибудь более правильное читать. Что именно?)
OR> чтобы понимать что означают всякие volatile и почему, скажем, на такое:
OR> extern const volatile unsigned uu;
OR> unsigned foo(void) { OR> return uu + uu; OR> }
OR> тем же IAR-ом генерится такой код:
OR> 3 unsigned foo(void) { OR> 4 return uu + uu; OR> \ __nearfunc unsigned int foo(); OR> \ foo: OR> \ 00000000 .... LDI R30,uu OR> \ 00000002 8120 LD R18,Z OR> \ 00000004 8131 LDD R19,Z+1 OR> \ 00000006 8100 LD R16,Z OR> \ 00000008 8111 LDD R17,Z+1 OR> \ 0000000A 0F02 ADD R16,R18 OR> \ 0000000C 1F13 ADC R17,R19 OR> \ 0000000E 9508 RET OR> 5 }
В данном случае в исходном тексте к переменной обращаются два раза. Если считать, что по стандарту положено "читать каждый раз", то в коде всё правильно. В моём же случае (++pwm == 1023) в тексте всего одно обращение к переменной. Вообще, в стандарте C++, что у меня есть (файл ansi_iso_iec_14882_1998.pdf), по делу нашёл следующее:
*1.9 Program execution* <...>
5 A conforming implementation executing a wellformed program shall produce the same observable behavior as one of the possible execution sequences of the corresponding instance of the abstract machine with the same program and the same input. However, if any such execution sequence contains an undefined operation, this International Standard places no requirement on the implementation executing that program rule,<...>
<...>
6 The observable behavior of the abstract machine is its sequence of reads and writes to volatile data and calls to library I/O functions.
Из этого вроде как следует, что последовательности чтения и записи volatile-объектов должны количественно совпадать для любого компилятора и любой машины. Больше никакого внятного упоминания о том, каковы же эти последовательности должны быть, найти не удалось.
<...>
11 The least requirements on a conforming implementation are: - At sequence points, volatile objects are stable in the sense that previous evaluations are complete and subsequent evaluations have not yet occurred.
Только то, что между точками следованя volatile-объекты должны принять состояние, соответствующее уже выполненным вычислениям, т.е. их значения нужно записать. Определение точки следования почему-то найти не удалось, но операция сравнения, вроде как, ей не является.
*5 Expressions* <...>
4 Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified. Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined. [Example: i = v[i++]; // the behavior is unspecified i = 7, i++, i++; // i becomes 9 i = ++i + 1; // the behavior is unspecified i = i + 1; // the value of i is incremented
-end example]
Тут у меня какие-то проблемы с пониманием около первого слова stored. Если кто-нибудь с хорошим знанием этого языка :-) переведёт, буду благодарен. Зато тут есть важное слово only. Его трактовка, конечно, зависит от того, что считать точкой следования, и что они подразумевают под "прежним значением", но на определённые мысли это наводит.
*7.1.5.1 The cv-qualifiers* <...>
8 [Note: volatile is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation. See 1.9 for detailed semantics. In general, the semantics of volatile are intended to be the same in C++ as they are in C. ]
Вот тут вот прошу обратить внимание на слово hint. Т.е. это всего лишь намёк избегать "агрессивной" оптимизации. Что считать "агрессивной", и насколько важно её избегать, найти, опять же, не удалось. По моему мнению, в первоначальном моём примере компилятор достоверно знал, что ничего с этой переменной случиться не может, и вполне мог исключить повторное чтение. Более того, он мог бы вообще разместить её в регистрах.
А вот, кстати, между прочим. Программа
#include <stdio.h>
int i = 0;
int& f(void) { puts("f()"); return i; }
int main(void) { int j = -1; printf("i = %d, j = %d\n", i, j); j = ++f(); printf("i = %d, j = %d\n", i, j); j = f()++; printf("i = %d, j = %d\n", i, j);
return 0; }
выдаёт следующее:
i = 0, j = -1 f() i = 1, j = 1 f() i = 2, j = 1
От добавления volatile результат не меняется, хотя в любом случае тут уж явно не до оптимизации -- вызов функции может повлечь побочные эффекты, поэтому не должен пропускаться.
В RU.C_CPP что ли спросить?..
|V|uxau/\