Hallo,
ausgegliedert, weil das Thema doch interessanter werden könnte als
ursprünglich gedacht. :-)
Ich werfe auch alle bisherigen Antworten mit hier rein.
//
------------------------------------------------------------------------
--------
Ich spiele etwas mit dem avr-gcc 10.1.0 rum und erhalte tausende
Warnungen die ich mit 9.3.0 nicht hatte.
"warning: compound assignment with 'volatile'-qualified left operand is
deprecated [-Wvolatile]"
Das bezieht sich immer auf solche kurzen Codezeilen wie zum Bsp.
1
TCCR1B|=_BV(CS11);// Prescaler 8
2
TCCR1B&=~(_BV(CS12)|_BV(CS11)|_BV(CS10));
Wie schreibt man das in modern? Ich meine das ist doch korrekt.
Desweiteren noch diese Warnung mit einer fremden Lib.
"warning: 'volatile'-qualified parameter is deprecated [-Wvolatile]"
Bezieht sich auf solche Codezeilen wie zum Bsp.
1
volatileuint8_thwserial_tx_pin
2
volatileuint8_tuart_mux
Hier werden alle volatile Member angemeckert. Laut Warnung ist das
veraltet? Wie lautet das in modern?
//
------------------------------------------------------------------------
----
von Oliver S.
Warnung abschalten. Alles andere wird kurtfristig nicht helfen. Ob dann
eher AVR aus dem gcc rausfliegt, oder das Problem gelöst wird, wird sich
zeigen.
//
------------------------------------------------------------------------
----
von Johann L.
Veit D. schrieb:
> "warning: compound assignment with 'volatile'-qualified left operand is> deprecated [-Wvolatile]"> "warning: 'volatile'-qualified parameter is deprecated [-Wvolatile]"
What you get is what you want!
> -std=gnu++20
Vielleicht solltest du dir das Kleingedruckte zu C++20 nochmal
durchlesen.
C++20 bringt zwar unglaublich moderne Features wie Werte für
mathematische Konstanten wie π auf die wir schon über 20 Jahre lang
warten. Aber auch:
• P1152R4, Deprecating volatile
Vielleicht die GCC Release Notes nochmal durchlesen?
http://gcc.gnu.org/gcc-10/changes.html#cxx
Oliver S. schrieb:
> Warnung abschalten. Alles andere wird kurtfristig nicht helfen. Ob dann> eher AVR aus dem gcc rausfliegt, oder das Problem gelöst wird, wird sich> zeigen.
Hä? Was hat das mit AVR zu tun???
//
------------------------------------------------------------------------
----
von Oliver S.
Nachtrag: Ganz so schlimm ist es doch nicht ;)
Veit D. schrieb:
> "warning: compound assignment with 'volatile'-qualified left operand is> deprecated [-Wvolatile]"> Das bezieht sich immer auf solche kurzen Codezeilen wie zum Bsp.TCCR1B> |= _BV(CS11); // Prescaler 8> TCCR1B &= ~( _BV(CS12) | _BV(CS11) | _BV(CS10) );>> Wie schreibt man das in modern? Ich meine das ist doch korrekt.
Da compound-assigment mit volatile nicht mehr gewünscht ist, musst du
das vermutlich (*) umschreiben in:
1
TCCR1B=TCCR1B|_BV(CS11);// Prescaler 8
2
TCCR1B=TCCR1B&~(_BV(CS12)|_BV(CS11)|_BV(CS10));
Die Optimierung in ein einzelnes sbi, falls das register im passenden
Adressbereich liegt, macht der Compiler trotzdem.
(*) ich 'abe gar kein gcc 10 ;)
//
------------------------------------------------------------------------
----
von Oliver S.
Johann L. schrieb:
> Hä? Was hat das mit AVR zu tun???
Veit D. schrieb:
> für die Frage mach ich keinen extra Thread auf. ;-)>> Ich spiele etwas mit dem avr-gcc 10.1.0 rum und erhalte tausende> Warnungen die ich mit 9.3.0 nicht hatte.
//
------------------------------------------------------------------------
----
Hallo,
ich habs nachgelesen. Muss man auch erstmal finden, mit der P-Nummer
gings leichter. Danke.
Bspw.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1152r4.html
Nur werde ich immer noch nicht schlau daraus warum das jetzt angemeckert
wird. Also warum die Warnung eingebaut wurde und warum man die
Kurzschreibweisen langfristig weg haben möchte. Warum denn überhaupt?
Ich sehe da keinen Sinn drin. Auch in Bezug auf volatile Variablen sehe
ich keinen Sinn drin.
Damit sind weltweit gefühlt 99% aller Codezeilen veraltet. Es kann ja
keine Alternative sein alle Kurzschreibweisen durch ihre Langversionen
zu ersetzen. Zudem ++count oder count++ um Welten leicher lesbar ist.
Man kann es mit "-Wno-deprecated" abschalten. Welchen negativen
Rattenschwanz das nach sich zieht kann ich nicht einschätzen. Also vor
was dann alles sinnvolles nicht mehr gewarnt wird. Oder bezieht sich der
Schalter wirklich nur auf diese "volatile deprecated" Warnung?
Veit D. schrieb:> Man kann es mit "-Wno-deprecated" abschalten.
Das schaltet aber alle deprecated-Warnungen ab, nicht nur die zu
volatile.
Nimm lieber nur die spezifischen raus, die Warnung sagt dir ja, welche
das jeweils ist.
Zum Thema selber, das wird eine größerer Baustelle.
Meine Einschätzing der Situation ist die:
Der Sinn der Abschaffung ist die völlig unklare Definition dessen, was
volatile in den einzelnen Fällen tatsächlich bedeutet. Alle Fälle, die
mehrdeutig oder auch völlig sinnlos waren, fliegen jetzt raus.
Das wird gerade im embedded- und Treiberbereich einige Aufräumarbeiten
in altem Code benötigen - wenn man denn C++20 mit altem Code benutzen
will oder muß.
stackoverflow liefert eigentlich nur einen link auf das hier:
https://www.youtube.com/watch?v=KJW_DLaVXIY
Der erklärt zwar das ein- oder andere, aber so richtig zufriedenstellend
ist die Situation nicht.
Oliver
Hallo,
habs mir angeschaut. Zusammengefasst wurde viel geredet, aber das
angebliche Problem mit dem increment/decrement nicht erklärt. Nur eine
pauschale Aussage am Ende "Goal 2/7 ... remove confusion". Die Frage
lautet: Welche Confusion? Der Syntax ist doch glasklar. Und wenn es
Probleme mit den Schlüsselwörtern gibt und deren unsägliche
Mehrfachbedeutung, ich erinnere an 'static', dann müßten sie bei den
Schlüsselwörtern endlich einmal aufräumen, neue einführen und die
Bedeutung konzentrieren. Alles andere ist in meinen Augen rumdoktern auf
der falschen Baustelle.
Mir ist bis jetzt nicht klar was an dem Syntax veraltet sein soll. Wie
gesagt, die Langversion kann keine Lösung sein.
// warning: '--' expression of 'volatile'-qualified type is deprecated
[-Wvolatile]
volatile int count;
...
...
--count;
Also entweder ist das eine falsche Warnung die gar nicht auftauchen
dürfte oder ich weiß auch nicht weiter was die gcc Entwickler sich dabei
gedacht haben. Schulter zucken.
Wenn ich 'volatile' verwende, dann hat das einen Grund. Ich sage damit
dem Compiler das er es nicht optimieren darf, eben weil es außerhalb von
seinem Sichtbereich verändert wird. Welche Schreibweise ich dann beim
decrement verwende ändert doch letztlich am Code nichts. Das eine wird
angemeckert, dass andere nicht. Ergibt absolut keinen Sinn.
Das soll jetzt kein Bashing gegen gcc sein, Nein, nur aufregen wird man
sich ja einmal dürfen ...
Veit D. schrieb:> Welche Schreibweise ich dann beim> decrement verwende ändert doch letztlich am Code nichts. Das eine wird> angemeckert, dass andere nicht. Ergibt absolut keinen Sinn.
Ein bisschen schon.
Bei den Verbundoperatoren sieht man auf die Schnelle nicht, dass im
Operator schon ein Race passieren kann, da read-modify-write.
So einen Verbundoperator ausschreiben bedeutet ja praktisch, dieses
potentielle Race ausdrücklich zu formulieren:
1
volatileintx;
2
3
/* Hm. */
4
x&=0xF0;
5
6
/* Ganz klar: lesen, ver-und-en, zuweisen */
7
x=x&0xF0;
Das sind alles so Dinger, die man bisher mit viel wohlwollen irgendwie
so gehandhabt hat, dass möglichst wenig kaputtgeht. Auch volatile Member
von Strukturen waren so ein Ding, insofern ists schon nicht verkehrt,
das endlich aufzuklären.
Veit D. schrieb:> Hallo,>> habs mir angeschaut. Zusammengefasst wurde viel geredet, aber das> angebliche Problem mit dem increment/decrement nicht erklärt.
Doch wird es @ 7:25
https://youtu.be/KJW_DLaVXIY?t=445
Das ist doch aber in beiden Fällen genau das Gleiche. Der Compiler weiß
doch beim übersetzen in beiden Fällen was zu tun ist. x lesen verunden
und zurückschreiben. Was soll er denn sonst machen? Zum verunden muss er
zwangseise x lesen und danach das Ergebnis zurückschreiben. Egal wie er
das macht. Genauso beim inkrementieren.
Vincent H. schrieb:> Veit D. schrieb:>> Hallo,>>>> habs mir angeschaut. Zusammengefasst wurde viel geredet, aber das>> angebliche Problem mit dem increment/decrement nicht erklärt.>> Doch wird es @ 7:25> https://youtu.be/KJW_DLaVXIY?t=445
Wird nicht erklärt. Was ist soll denn schief gehen?
Oliver S. schrieb:> Das schaltet aber alle deprecated-Warnungen ab, nicht nur die zu> volatile.> Nimm lieber nur die spezifischen raus, die Warnung sagt dir ja, welche> das jeweils ist.
Meinst du diesen Schalter? -Wno-volatile Oder ist der noch zu grob?
Hallo,
tut mir leid, ich verstehe das eigentliche Problem was damit gelöst
werden soll immer noch nicht. Der Syntax muss doch erstmal aufgelöst
werden bevor damit irgendwas gemacht wird. Das heißt die
Kurzschreibweise muss doch vorher in die Langschreibweise gewandelt
werden bevor er das macht was eigentlich gemacht werden soll. Wenn hier
etwas schief gehen könnte, dann wäre das schon seit Urzeiten schief
gegangen. Ging es aber bis jetzt nicht. Demnach sehe ich nachwievor kein
Problem was gelöst werden müßte.
Veit D. schrieb:> Das heißt die Kurzschreibweise muss doch vorher in die Langschreibweise> gewandelt werden
Moment mal: der ganze Zirkus betrifft C++, und dort wird der Operator &=
meines Wissens separat von & und Zuweisung überladen.
Veit D. schrieb:> ich weiß auch nicht weiter was die gcc Entwickler sich dabei gedacht> haben
Du meckerst auf die Falschen (zumindest teilweise – natürlich möglich,
dass auch solche das in der C++-Normierung mit vorangetrieben haben):
das Ganze betrifft Änderungen im C++-Standard, nicht irgendwelche
Marotten von GCC allein.
Stellt sich natürlich die Frage, ob sich C++ mit derartigen
Entwicklungen nicht von den Lowlevel-Embedded-Entwicklern entfernt, denn
diese werden all ihre (oft über Headerfiles der Hersteller) als volatile
deklarierten Hardwarezugriffe sicher nicht umschreiben wollen.
Die Sprache C ist m.W. davon nicht betroffen.
Veit D. schrieb:> Wenn hier> etwas schief gehen könnte, dann wäre das schon seit Urzeiten schief> gegangen. Ging es aber bis jetzt nicht. Demnach sehe ich nachwievor kein> Problem was gelöst werden müßte.
Doch, es ist häufig seit Urzeiten schief gegangen. Oder anders
ausgedrückt: Das vieles anscheinend funktioniert hat, war Zufall oder
zumindest wohlwollendes Zuvorkommen der Compilerbauer.
Nur mal ein Beispiel:
https://www.kdab.com/getting-rid-of-volatile-in-some-of-qt/
Volatile im Zusammenhang mit memory-mapped Registerzugriffen wird ja
weiterhin zulässig sein, ebenso alle Operationen da drauf, die man
benötigt. Alle irgendwie zwei- oder uneindeutigen Verwendungen fliegen
halt raus.
Da muß man dann halt einiges umschreiben.
Oliver
Oliver S. schrieb:> Volatile im Zusammenhang mit memory-mapped Registerzugriffen wird ja> weiterhin zulässig sein, ebenso alle Operationen da drauf, die man> benötigt.
Das widerspricht allerdings obiger Warnung, denn was dort gemacht wird,
ist ja exakt das: volatile auf Hardware-Register.
Oliver S. schrieb:> Die erste Warnung bezieht sich auf das Compound-Assignment, nicht auf> die Variablendeklaration selber.
Einen Sinn sehe ich darin allerdings nicht, das zu deprecaten.
Aber gut, mit derartigen Aktionen brauche ich keine Gedanken mehr daran
verschwenden, ob wir vielleicht in $FIRMA mal irgendwie für unsere
Firmwareprojekte künftig von C auf C++ schwenken sollten. Mag ja dies
oder jenes in C++ eleganter auszudrücken sein, aber derartige Kapriolen
des Standards sind mir dann einfach zu wenig zukunftssicher. Nur, weil
da ein paar Leute am grünen Tisch eine Idee hatten, möchte ich nicht
aller paar Jahre hinterher hecheln und sinnlos die Firmware umschreiben,
nur damit sie wieder warning free ist.
Klar, sagt ja keiner, dass man unbedingt auf C++<neueste Version> gehen
muss – aber es sagt eben auch keiner, dass man dann unbedingt überhaupt
auf C++ gehen muss.
Allerdings gelten die Argumente für die Änderungen genauso für C wie
C++. Insofern könnt es passieren, daß der nächste C-Standard da auf
ähnliche (oder besser gleiche) Ideen kommt.
Schaun wer mal...
Oliver
Oliver S. schrieb:> Allerdings gelten die Argumente für die Änderungen genauso für C wie> C++.
Naja, in C++ ist a &= b ein separater Operator. In C ist es wirklich nur
eine Kurzform von a = a & b. Daher verstehe ich absolut nicht, warum man
zweites gestatten sollte, erstes aber nicht.
C:\Atmel_Toolchain\AVR8_GCC\avr-gcc-10.0.0_2019-12-16_-mingw32\avr\inclu
de\avr\sfr_defs.h
***********************************************************************
128 #define _MMIO_BYTE(mem_addr) (*(/*volatile*/ uint8_t *)(mem_addr))
Ein Beispiel kompiliert fehlerfrei mit geändertem non-volatile
MMIO_BYTE(mem_addr)
Ob das Programm auch noch das tut was es soll kann ich erst gegen Abend
testen.
A. B. schrieb:> Ein Beispiel kompiliert fehlerfrei mit geändertem non-volatile> MMIO_BYTE(mem_addr)
Das klingt nach keiner guten Idee. Das volatile dort muß schon bleiben,
und ist ja auch mit C++20 kein Problem.
Mit C sowieso nicht...
Oliver
Jörg W. schrieb:> In C ist es wirklich nur> eine Kurzform von a = a & b. Daher verstehe ich absolut nicht, warum man> zweites gestatten sollte, erstes aber nicht.
Dachte ich bis jetzt auch....
https://docs.microsoft.com/de-de/cpp/c-language/c-compound-assignment?view=vs-2019
"Allerdings ist der Verbundzuweisungsausdruck nicht mit der erweiterten
Version äquivalent, da der Verbundzuweisungsausdruck expression1 nur
einmal auswertet, während die erweiterte Version expression1 zweimal
auswertet: in der Additions- und in der Zuweisungsoperation."
Gilt das dann auch für alle C Compiler?
>> schreiben zu müssen – den wirklichen Mehrwert davon müsste mir erstmal> jemand erläutern.>> Den Minderwert dagegen erkenne ich sofort: unreadability.
Das bleibt ein Sonderfall.
Normalerweise geht es mit
1
r.set<xBit>();
Hier gleich mit Typsicherheit, denn das Register r in diesem Beispiel
lässt nur bestimmte Bit-Typen zu.
Teo D. schrieb:> "Allerdings ist der Verbundzuweisungsausdruck nicht mit der erweiterten> Version äquivalent, da der Verbundzuweisungsausdruck expression1 nur> einmal auswertet, während die erweiterte Version expression1 zweimal> auswertet: in der Additions- und in der Zuweisungsoperation.">> Gilt das dann auch für alle C Compiler?
So stehts tatsächlich im Standard.
Oliver
Oliver S. schrieb:> So stehts tatsächlich im Standard.
Das hat natürlich vor allem dann Auswirkungen, wenn man mit einem Makro
drauf zugreift. Der wird natürlich in der ausgeschriebenen Variante
zweimal evaluiert. Oder aber wenn da ein Funktionsaufruf drin vorkommt
oder dergleichen.
Solange da nur eine feste (IO-Register-)Adresse drin steht, ist der
Effekt nicht wichtig, dann wird genau einmal lesend und einmal
schreibend zugegriffen in beiden Fällen. Es ist und bleibt ein
read-modify-write, und jedem, der damit zu tun hat, sollte das klar
sein.
Wilhelm M. schrieb:> r.set<xBit>();
Allerdings ist da das read-modify-write nicht mehr und nicht minder
„verschleiert“ als beim compound-Operator.
Insofern kaufe ich diese Argumentation nach wie vor nicht ab.
Jörg W. schrieb:> Solange da nur eine feste (IO-Register-)Adresse drin steht, ist der> Effekt nicht wichtig, dann wird genau einmal lesend und einmal> schreibend zugegriffen in beiden Fällen. Es ist und bleibt ein> read-modify-write, und jedem, der damit zu tun hat, sollte das klar> sein.
avr-gcc z.B. übersetzt |= in ein sbi, wenn das geht. Da gibt es dann
überhaupt kein read.
Oliver
Wilhelm M. schrieb:> Au weiua!!!!
*****************
klar, das ist ein HACK, aber da kommt das volatile her
*****************
Mit volatile MMIO_BYTE(mem_addr) hängt avr-gcc-10.0.0 in den
member-functions mit compound operatoren.
************************************************************
Wenn ich das oben zitierte Paper überfliege, sollte volatile eigentlich
doch genau für den Zugriff auf Register zulässig sein.
****************
namespace Mcucpp
{
#define IO_REG_WRAPPER(REG_NAME, CLASS_NAME, DATA_TYPE) \
struct CLASS_NAME\
{\
typedef DATA_TYPE DataT;\
static DataT Get(){return REG_NAME;}\
static void Set(DataT value){REG_NAME = value;}\
static void Or(DataT value){REG_NAME |= value;}\
static void And(DataT value){REG_NAME &= value;}\
static void Xor(DataT value){REG_NAME ^= value;}\
static void AndOr(DataT andMask, DataT orMask){REG_NAME = (REG_NAME
& andMask) | orMask;}\
template<int Bit>\
static bool BitIsSet(){return REG_NAME & (1 << Bit);}\
template<int Bit>\
static bool BitIsClear(){return !(REG_NAME & (1 << Bit));}\
}
Oliver S. schrieb:> avr-gcc z.B. übersetzt |= in ein sbi, wenn das geht. Da gibt es dann> überhaupt kein read.
Doch, natürlich auch. Wird halt von der Hardware erledigt.
Daher findest du in den AVR-Datenblättern auch Warnungen wie:
1
Do not use Read-Modify-Write instructions (SBI and CBI) to set or clear
2
the MPCM bit. The MPCM bit shares the same I/O location as the TXC Flag
3
and this might accidentally be cleared when using SBI or CBI instructions.
Der einzige wesentliche Unterschied zu explizitem read-modify-write: SBI
und CBI sind atomar (und sie sind schneller, gut).
ps: AVR-GCC übersetzt natürlich auch
Jörg W. schrieb:> Daher findest du in den AVR-Datenblättern auch Warnungen wie:
...
Das gilt für die älteren Typen aus der Ära Mega128. Alle neueren machen
sbi/cli ohne read/modify/write auf das ganze Register, die setzen das
Bit direkt.
Oliver
Ich habe jetzt aus purer Neugierde den Thread gelesen und musste bei
Olivers Beiträgen ständig nicken. Jetzt komme ich ja eher aus
Hochsprachen und benutze C und Assembler nur zur Not zum besonders
schnellen Bit-Schubsen, aber da sollte man schon wissen, was man tut.
Was die neuen Standards sollen, ist schlicht Lesbarkeit schaffen. g++
-O3 oder g++ -Os -fno-align... optimieren sowieso so gut wie alles weg,
was überflüssig ist.
Ich bin mal so dreist und empfehle auch auf ATtinys und PIC12s TDD ;)
PS: Außer den nativen Intel- und besonders den nativen nVidia-Compilern
gilt die GCC (GNU Compiler Collection) nach wie vor als die, die bei so
gut wie jedem Target (Ausnahme: die alten HP-Risc Prozessoren und
teilweise SunSparcs) das schnellste Kompilat erzeugt.
Man muss kein Assembler können, aber wenn man diff auf dem System hat,
kann man prima vergleichen, was g++ mit den entsprechenden Parametern so
alles "weg macht".
Oliver S. schrieb:> Das gilt für die älteren Typen aus der Ära Mega128.
Vergleichbare Bemerkungen findest du auch in den Datenblättern neuerer
AVRs, hier bspw. ATmega1284:
1
The receive buffer consists of a two level FIFO. The FIFO will change
2
its state whenever the receive buffer is accessed. Due to this behavior
3
of the receive buffer, do not use Read-Modify-Write instructions (SBI and
4
CBI) on this location. Be careful when using bit test instructions
5
(SBIC and SBIS), since these also will change the state of the FIFO.
Wie sollte es in der Hardware auch sonst funktionieren?
Oliver S. schrieb:> Jörg W. schrieb:>> Solange da nur eine feste (IO-Register-)Adresse drin steht, ist der>> Effekt nicht wichtig, dann wird genau einmal lesend und einmal>> schreibend zugegriffen in beiden Fällen. Es ist und bleibt ein>> read-modify-write, und jedem, der damit zu tun hat, sollte das klar>> sein.>> avr-gcc z.B. übersetzt |= in ein sbi, wenn das geht. Da gibt es dann> überhaupt kein read.>> Oliver
Das ist dann wohl ein Bug, wenn |= mit einem volatile "left operand" ein
sbi ergibt?
mh schrieb:> Das ist dann wohl ein Bug, wenn |= mit einem volatile "left operand" ein> sbi ergibt?
Warum?
Das SBI macht genau das, was da gewünscht wird.
Lange Zeit konnte der Compiler das leider nicht, und stattdessen wurden
überall inline-asm-Makros für sbi() und cbi() benutzt, um auf die
entsprechenden Features der Controller zugreifen zu können.
Carsten P. schrieb:> Was die neuen Standards sollen, ist schlicht Lesbarkeit schaffen.
Genau das sehe ich damit allerdings eben nicht erreicht.
Carsten P. schrieb:> gilt die GCC (GNU Compiler Collection) nach wie vor als die, die bei so> gut wie jedem Target […] das schnellste Kompilat erzeugt.
Mittlerweile dürfte wohl llvm da meist die Nase vorn haben, und gerade
im hier diskutierten Controllerbereich war GCC auch eher der zweite
Sieger hinter sowas wie IAR.
Jörg W. schrieb:> Das SBI macht genau das, was da gewünscht wird.
Ich habe nicht viel mit AVRs zu tun. Alle Quellen, die ich zum SBI
finden konnte, haben verschwiegen, dass ein read-modify-write
stattfindet. Überall steht "set a bit". Und wenn unter anderem das "AVR
Instruction Set Manual" "set a bit" sagt, gehe ich davon aus, das genau
das passiert und kein r-m-w.
A. B. schrieb:> Wenn ich das oben zitierte Paper überfliege, sollte volatile eigentlich> doch genau für den Zugriff auf Register zulässig sein.
Ja genau. Ist es auch und genau dafür gedacht. Nur ist die Semantik der
compound-statements "unklar". Daher das deprecated und besser einen
expliziten RMW.
Die mega0 und tiny1 habe die xxxCLR und xxxSET bzw. Flagregister, da
reicht der Zuweisungsoperator (kein compound) , um atomar ein Bit zu
setzen oder zu löschen.
Jörg W. schrieb:> Vergleichbare Bemerkungen findest du auch in den Datenblättern neuerer> AVRs, hier bspw. ATmega1284:>...
Ich sag mal, ohne das getestet zu haben, das könnte einer der (leider
üblichen) copy und paste-Fehler im Datenblatt sein.
Testen lässt sich das nicht, weil UDRn bei den Prozessoren ausserhalb
des sbi/cbi-Adressbereichs liegt, und die Befehle daher auf das Register
gar nicht angewendet werden können.
mh schrieb:> Das ist dann wohl ein Bug, wenn |= mit einem volatile "left operand" ein> sbi ergibt?
Nee, das ist ein gewolltes Feature.
mh schrieb:> Ich habe nicht viel mit AVRs zu tun. Alle Quellen, die ich zum SBI> finden konnte, haben verschwiegen, dass ein read-modify-write> stattfindet. Überall steht "set a bit".
Bei den alten Typen steht explizit dabei, daß die ein read/modify/write
auf das ganze Register machen.
Oliver
Wilhelm M. schrieb:> Nur ist die Semantik der compound-statements "unklar".
Für mich nicht, für viele andere auch nicht.
Tut mir leid, ich kann die Gedankengänge der Standardisierer hier
absolut nicht nachvollziehen.
Hallo,
hab auf diversen Seiten nachgelesen. Zwischen a = a + b und a += b gibt
es keinen Unterschied. Beide Syntaxe sind gleichwertig. Es wird immer
von rechts nach links gelesen. Habe auch im C++11 Buch von Stroustrup
nachgelesen. Absolut gleichwertig. Der Mann muss es schließlich wissen
was er erfunden hat.
Ein Auszug:
1
11.1.4 Inkrementieren und Dekrementieren
2
Mit dem Operator ++ lässt sich das Inkrementieren direkt ausdrücken, anstatt indirekt eine Kombination von Addition und Zuweisung zu verwenden. Vorausgesetzt, dass lvalue keine Nebeneffekte aufweist, ist ++lvalue dasselbe wie lvalue+=1, was wiederum lvalue=lvalue+1 bedeutet. Der Ausdruck, der das zu inkrementierende Objekt bezeichnet, wird (nur) einmal ausgewertet. Das Dekrementieren wird analog dazu mit dem Operator -- ausgedrückt.
3
4
Die Operatoren ++ und -- können sowohl als Präfix- als auch als Postfixoperatoren verwendet werden. Der Wert von ++x ist der neue (d. h. inkrementierte) Wert von x. Zum Beispiel ist y=++x gleichbedeutend mit y=(x=x+1). Dagegen ist der Wert von x++ der alte Wert von x. Zum Beispiel ist y=x++ äquivalent zu y=(t=x,x=x+1,t), wobei t eine Variable desselben
5
Typs wie x ist.
Ich hätte gern einmal ein konkretes Bsp. wo einfaches inkrement schief
gegangen ist.
Was die Lesbarkeit betrifft. Es wird immer komplizierter. Das Werkzeug
zu benutzen wird mit jeder neuen Version verkompliziert. Das ist nicht
der Sinn eines Werkzeuges. Das Zauberwort ist Schlichtheit. Keine
Überfrachtung. Konzentrierung auf das Wesentliche. Dadurch und nur
dadurch werden Fehler vermieden. Es werden keine Fehler vermieden wenn
alles unleserlich wird. Das zieht sich durch alle Bereiche des Lebens.
Ich meine was will ein Programmierer mit x++ oder x += 2 denn sonst
ausdrücken wie x = x + 1 oder x = x + 2? Das ist gängige Praxis in
Millionen von Codezeilen. Wenn da irgendjemand ein Problem sieht, was es
laut meiner Überzeugung nachwievor nicht gibt, dann sollte man unter der
Haube dafür Sorgen das beide Syntaxe gleich behandelt werden. Anstatt
dem gemeinen Programmierer Knüppel zwischen die Beine zu werfen.
Dieses load und store kann nun wirklich nicht deren ernst sein.
Habe ich mich im Video schon an den Kopf gefasst.
volatile_store(&FOOREG, volatile_load(&FOOREG) | BIT);
Wer soll das lesen? Das ist totaler Krampf. Totaler Nonsens. Da geht mir
die Hutschnur hoch.
Da kann man dann auch gleich die Langversion schreiben was wenigstens
lesbar bleibt.
FOOREG = FOOREG | BIT;
Wenn man das alles mal mit gebührenden Abstand betrachtet, dann ist
vielleicht Assembler lernen um Welten einfacher wie jetzt frisch mit C++
anzufangen. Meine feste Überzeugung ist folgende. Die C++ Entwickler
stecken viel zu tief in ihren Bits und Bytes drin und sehen die reale
Programmiererwelt nicht mehr. Sie erkennen nicht welche harten Probleme
sie mit vermeintlichen Erleichterungen schaffen die praktisch keine
sind. Dabei reden wir nur von dem einen Bsp. hier.
Ich bin da genau der gleichen Meinung wie Jörg. Was hier für ein Mist
verzapft wurde kann niemand logisch nachvollziehen. Das sind nur
aufgeblasene Probleme die keine sind und verursachen nur sinnfreien
Mehraufwand.
Veit D. schrieb:> Die C++ Entwickler stecken viel zu tief in ihren Bits und Bytes drin und> sehen die reale Programmiererwelt nicht mehr.
Sie stecken meiner Meinung nach mehrere Etagen über den Bits und Bytes.
Veit D. schrieb:> Vorausgesetzt, dass lvalue keine Nebeneffekte aufweist, ist ++lvalue> dasselbe wie lvalue+=1, was wiederum lvalue=lvalue+1 bedeutet.
Da hast Du es doch.
Veit D. schrieb:> hab auf diversen Seiten nachgelesen. Zwischen a = a + b und a += b gibt> es keinen Unterschied. Beide Syntaxe sind gleichwertig.
Nein, sind sie nicht, steht ja schon weiter oben.
Im C- und C++-Standard steht:
"A compound assignment of the form E1 op= E2 is equivalent to the simple
assignment expression E1 = E1 op (E2), except that the lvalue E1 is
evaluated only once, and with respect to an indeterminately-sequenced
function call, the operation of a compound assignment is a
single evaluation. "
Genau dort, wo es im Zusammenhang mit volatile wichtig wird, liegt der
Unterschied.
Oliver
Wilhelm M. schrieb:> Veit D. schrieb:>> Vorausgesetzt, dass lvalue keine Nebeneffekte aufweist, ist ++lvalue>> dasselbe wie lvalue+=1, was wiederum lvalue=lvalue+1 bedeutet.>> Da hast Du es doch.
Was habe ich denn hier?
"ist ++lvalue dasselbe wie lvalue+=1, was wiederum lvalue=lvalue+1
bedeutet."
Welchen Nebeneffekt soll lvalue denn haben können?
Oliver S. schrieb:> Genau dort, wo es im Zusammenhang mit volatile wichtig wird, liegt der> Unterschied.
Wenn man auf diesem Unterschied herum reitet, wäre es allerdings um so
wichtiger, das compound statement gerade nicht zu verhindern.
Veit D. schrieb:> Welchen Nebeneffekt soll lvalue denn haben können?
Genau deswegen hat man sie als volatile gekennzeichnet, weil es
irgendwelche(!) Effekte sind.
Wilhelm M. schrieb:> Veit D. schrieb:>> Welchen Nebeneffekt soll lvalue denn haben können?>> Genau deswegen hat man sie als volatile gekennzeichnet, weil es> irgendwelche(!) Effekte sind.
Ich frage nochmal. Welche Effekte?
Jörg W. schrieb:> Wilhelm M. schrieb:>> Nur ist die Semantik der compound-statements "unklar".>> Für mich nicht, für viele andere auch nicht.>> Tut mir leid, ich kann die Gedankengänge der Standardisierer hier> absolut nicht nachvollziehen.
Ok dann überprüfen wir mal wie klar oder unklar die Semantik von
"compound assignments" wie |= ist. |= ist assignment operator. Der
Standard sagt zur Semantik von "assignment operators"
1
An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the left operand after
2
the assignment, but is not an lvalue.
Der Wert einer "assignment expression" ist also der Wert des "left
operands" nach der Zuweisung. Wenn der "left operand" jetzt eine
volatile Variable ist, müsste die Variable nach der Zuweisung nochmal
gelesen werden, um ihren Wert zu bestimmen. Der Wert der volatile
Variable muss ja nicht dem entsprechen, was zuletzt rein geschrieben
wurde. Dementsprechend müsste in
1
volatileintvar;
2
var|=5;
die Variable var also 2 mal gelesen und ein mal geschrieben werden.
Ich wurde allerdings vor kurzem darauf hingewiesen, dass das nicht
stimmt und dass sich dieser Abschnitt in der aktuellen Version des
Standards geändert hat. Dort steht jetzt
1
An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the left operand after
2
the assignment,113) but is not an lvalue.
3
4
113) The implementation is permitted to read the object to determine the value but is not required to, even when the object has volatile-qualified type.
Scheint also nicht so eindeutig zu sein.
Damit ist jetzt übrigens
Veit D. schrieb:> Welche Effekte?
Das ist bei volatile natürlich erstmal dem Compiler verborgen.
Aber wenn man schon darauf aus ist, dass der compound operator den
lvalue nur einmal anfasst und die anderen zweimal, dann nimmt man mit
dem Verbot des compound operators jegliche Möglichkeit, überhaupt mit
nur einer Evaluierung des lvalues zu hantieren.
"A compound assignment of the form E1 op= E2 is equivalent to the simple
2
assignment expression E1 = E1 op (E2), except that the lvalue E1 is
3
evaluated only once, and with respect to an indeterminately-sequenced
4
function call, the operation of a compound assignment is a
5
single evaluation."
Wenn E2 mit E1 irgendwas op machen muss, dann muss doch E1 erstmal
gelesen werden. Ansonsten kann keine op ausgeführt werden. Mir konnte im
gesamten Thread noch niemand das Problem darlegen was dabei schief gehen
soll, weil jeder nur antwortet "kann schief gehen". Von dem was schief
gehen kann redet bis jetzt niemand. Das ist das eigentliche Problem in
der gesamten Diskussion. Da helfen auch keine Zitate die nichts anderes
aussagen.
Jörg W. schrieb:> Oliver S. schrieb:>> Das gilt für die älteren Typen aus der Ära Mega128.>> Vergleichbare Bemerkungen findest du auch in den Datenblättern neuerer> AVRs, hier bspw. ATmega1284:
.
>
1
> The receive buffer consists of a two level FIFO. The FIFO will change
2
> its state whenever the receive buffer is accessed. Due to this behavior
3
> of the receive buffer, do not use Read-Modify-Write instructions (SBI
4
> and
5
> CBI) on this location. Be careful when using bit test instructions
6
> (SBIC and SBIS), since these also will change the state of the FIFO.
7
>
>> Wie sollte es in der Hardware auch sonst funktionieren?
Das ist aber auch ein ganz spezielles Register. Ob man wirklich einzelne
Bits in den SendeFifo schreiben will. Ich lade da immer das nächste zu
sendende Byte ab bzw. hole hole ein empfangenes Byte ab. Es gibt diese
Warnung sicher auch für Int-Flags, die durch schreiben eines "1"-Bits
quittiert werden müssen, aber nicht generell für Port-Bits. Andernfalls
würde ganz viel meines AVR-Codes (in der Regel C++) nicht funktionieren.
Das ganze Thema scheint auch im Standardisierungskommittee noch zu
Diskussionen zu führen.
C++20 wird zunächst ja nur die deprecated-Fälle nennen, die Nutzung ist
aber noch nicht ungültig. C++23 sollte das dann umsetzten.
Nach dem Paper hier wird aber „strongly recommended“, die Umsetzung auf
C++26 zu verschieben.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2139r0.html#3.5
Zitat:
„ As outright removal is introducing potential breakage into programs
that have been compiling successfully since C++98, this paper strongly
recommends to hold this feature in Annex D as deprecated for another 3
years, and strongly consider taking further action for C++26.“
Bis dahin fließt noch viel Wasser den Rhein herunter.
Oliver
Hallo,
irgendwie wird mir hier zu viel mit unterschiedlichen Bedeutungen von
volatile rumgewurfen.
1
Der Wert der volatile Variable muss ja nicht dem entsprechen, was zuletzt rein geschrieben
2
wurde.
Das kann nicht stimmen. Denn volatile sagt dem Compiler vertraue nie
darauf das du den aktuellen Wert kennst, deshalb lese ihn immer frisch
aus bevor du damit etwas machst.
Mir missfällt das man versucht von hinten durch die Brust durch das Auge
irgendwas umzubiegen.
// ------------------------------------
>> Welche Effekte?> Das ist bei volatile natürlich erstmal dem Compiler verborgen.> Aber wenn man schon darauf aus ist, dass der compound operator den> lvalue nur einmal anfasst und die anderen zweimal, dann nimmt man mit> dem Verbot des compound operators jegliche Möglichkeit, überhaupt mit> nur einer Evaluierung des lvalues zu hantieren.
Sehe ich genauso. Es ist mit dem Schlüsselwort 'volatile' klar geregelt
welche Bedeutung das hat. Siehe oben. Wenn der Compiler bis jetzt damit
Mist gemacht haben sollte, dann muss man das wie schon gesagt unter der
Haube korrigieren. Alles andere ist ganz groooßer Mist. Da sind wir zwei
uns zumindestens einig. So deute ich das jedenfalls.
Andererseits habe ich noch nie etwas von vemeintlichen Probleme gelesen
die ein Programmierer gehabt hätte. Weder hier im Forum noch woanders.
Ich kann nur hoffen das das Problem im Standardisierungskommittee auch
wirklich ernsthaft angekommen ist und es dann eine bessere Lösung dafür
gibt.
Carl D. schrieb:> Warnung sicher auch für Int-Flags, die durch schreiben eines "1"-Bits> quittiert werden müssen, aber nicht generell für Port-Bits.
Da ist das Datenblatt eindeutig. Single-Bit-sbi/cbi kann in den
Rgeistern überall für einzelne Bits ohne Probleme benutzt werden.
Der Standardsatz lautet dort immer:
„ Some of the Status Flags are cleared by writing a logical one to them.
Note that, unlike most other AVRs, the CBI and SBI instructions will
only operate on the specified bit, and can therefore be used on
registers containing such Status Flags. The CBI and SBI instructions
work with registers 0x00 to 0x1F only.“
Oliver
Veit D. schrieb:> Das kann nicht stimmen. Denn volatile sagt dem Compiler vertraue nie> darauf das du den aktuellen Wert kennst, deshalb lese ihn immer frisch> aus bevor du damit etwas machst.
Das stimmt eben nicht. Siehe Fußnote 113 in dem Zitat aus dem aktuellen
Standard. Der Compiler darf bei Zuweisungen davon ausgehen, dass sich
der Wert nicht ändert. Er muss es aber nicht.
Veit D. schrieb:> Was habe ich denn hier?> "ist ++lvalue dasselbe wie lvalue+=1, was wiederum lvalue=lvalue+1> bedeutet."> Welchen Nebeneffekt soll lvalue denn haben können?
An der Stelle sollte man auch mal drüber nachdenken was nach
Oliver S. schrieb:> „ Some of the Status Flags are cleared by writing a logical one to them.> Note that, unlike most other AVRs, the CBI and SBI instructions will> only operate on the specified bit, and can therefore be used on> registers containing such Status Flags. The CBI and SBI instructions> work with registers 0x00 to 0x1F only.“
Steht das nicht im Widerspruch zu der obigen Aussage, dass SBI
read-modify-write macht?
mh schrieb:> dass SBI read-modify-write macht?
Daher steht da wohl auch "unlike most other AVRs". Er schreibt nur
nicht, in wessen Datenblatt das so ist.
"most other AVRs" machen offensichtlich r-m-w, aber eben dieser (oder
diese Familie) nicht.
mh schrieb:> Veit D. schrieb:>> Das kann nicht stimmen. Denn volatile sagt dem Compiler vertraue nie>> darauf das du den aktuellen Wert kennst, deshalb lese ihn immer frisch>> aus bevor du damit etwas machst.>> Das stimmt eben nicht. Siehe Fußnote 113 in dem Zitat aus dem aktuellen> Standard. Der Compiler darf bei Zuweisungen davon ausgehen, dass sich> der Wert nicht ändert. Er muss es aber nicht.
Da sind wird doch beim Punkt wovon die ganze Zeit die Rede ist. Warum
darf der Compiler von etwas anderem ausgehen was der Programmierer
niemals beabsichtigt? Wenn man den Compiler reparieren würde wäre das
Problem absolut unkompliziert gelöst. Macht man aber nicht. Man trägt
das Problem nach außen. Kopfschüttel!
> Veit D. schrieb:>> Was habe ich denn hier?>> "ist ++lvalue dasselbe wie lvalue+=1, was wiederum lvalue=lvalue+1>> bedeutet.">> Welchen Nebeneffekt soll lvalue denn haben können?>> An der Stelle sollte man auch mal drüber nachdenken was nach>
1
>externvolatileinta;
2
>intb=++a;
3
>
> der Wert von b ist.
Was soll da sein? a plus 1 und das Ergebnis wird b zugewiesen. Das ist
eindeutig. Auch laut Stroustrup.
Veit D. schrieb:> Was habe ich denn hier?> "ist ++lvalue dasselbe wie lvalue+=1, was wiederum lvalue=lvalue+1> bedeutet."> Welchen Nebeneffekt soll lvalue denn haben können?
Jeden nur denkbaren.
Siehe z.B das o.a. UDR-Register im AVR, bei dem zum einen Schreib- und
Lesezugriffe auf zwei verschiede Hardwareregister zugreifen (Receive-
und Transmitbuffer), und zudem ein Lesezugriff auf das Receiveregister
auch noch den Fifo um eine Position weiterschaltet.
In dem Fall ist ein +=1 zwar selten sinvoll, aber solche Hardwarergister
mit Nebenwirkungen gibt es irgendwo in irgendwelchen Bausteinen in allen
nur (un)denkbaren Ausführungen.
Oliver
Oliver S. schrieb:> Siehe z.B das o.a. UDR-Register im AVR, bei dem zum einen Schreib- und> Lesezugriffe auf zwei verschiede Hardwareregister zugreifen (Receive-> und Transmitbuffer), und zudem ein Lesezugriff auf das Receiveregister> auch noch den Fifo um eine Position weiterschaltet.
Ja, aber jemanden daran hindern zu wollen, dass er Unsinn verzapft (wie
eben UDR +=1 oder UDR |= 2) sollte nicht die Aufgabe eines
Standardkommittees sein. ;-)
Wenn du mit einer geladenen Pistole auf deinen Fuß zielst und abdrückst,
ist hinterher auch ein Loch drin. War an dem dann der Pistolenhersteller
schuld oder doch eher derjenige, der die Pistole bedient hat?
Veit D. schrieb:> Was soll da sein? a plus 1 und das Ergebnis wird b zugewiesen. Das ist> eindeutig. Auch laut Stroustrup.
Ok, da habe ich mich undeutlich ausgedrückt. Ich bin immer implizit von
Jörg W. schrieb:> aja, in C++ ist a &= b ein separater Operator. In C ist es wirklich nur> eine Kurzform von a = a & b.
ausgegangen und wollte darauf hinweisen, dass das in c auch alles andere
als klar ist. Die Auszüge oben sind auch aus dem c Standard. Also was
ist die Antwort wenn es c ist?
Auch ich versuche gerade, die Problematik von Compound-Assignments in
Verbindung mit volatile zu verstehen, allerdings bisher ohne Erfolg.
In allen Artikeln, die ich bisher darüber gelesen habe, steht sinngemäß,
die Semantik sei unklar bzw. mehrdeutig. Diese Aussage an sich ist für
mich aber zu abstrakt, um ein reales Problem darin zu erkennen.
Vielleicht kann jemand, der die Sache verstanden zu haben glaubt, die
Problematik an folgendem konkreten Beispiel erläutern:
Betrachten wir das folgende C++-Anweisung für einen ATtiny25:
1
PORTB|=0x01;
Das Makro PORTB wird dabei expandiert in
1
(*(volatileuint8_t*)((0x18)+0x20))
AVR-GCC 9.3.0 generiert daraus folgenden Assemblercode:
1
sbi 0x18,0
Das ist zunächst einmal genau das, was man sich wünscht.
Die Leute von Normungsgremium behaupten nun, die Semantik der obigen
Anweisung sei mehrdeutig. Das wirft für mich folgende Fragen auf:
- Wie sehen die verschiedenen Semantiken, die in die Anweisung
hineininterpretiert werden können, konkret aus?
- Welchen Assemblercode könnte ein C++17-konformer Compiler unter
böswilligster Ausnutzung der genannten Mehrdeutigkeit daraus
generieren?
- Wie müsste die Anweisung (ohne die Verwendung von vordefinierten
Makros oder Templates) geschrieben werden, damit die Semantik
eindeutig ist und dem Compiler immer noch die Möglichkeit gegeben
wird, daraus die gewünschte SBI-Instruktion zu generieren?
mh schrieb:> Also was ist die Antwort wenn es c ist?
Die Antwort ist: der Wert von b ist, was auch immer aus a ausgelesen
werden kann nach dieser Operation.
Es kann doch nicht Aufgabe des Standards sein, die Programmierer vor
selbst produziertem Unfug zu erretten. Wenn a halt irgendwas in Hardware
ist, aus dem man immer 0 ausliest (bspw.), dann ist das Unfug seitens
des Programmierers, so ein b = ++a überhaupt hinzuschreiben. Da muss man
nicht das ++a deshalb deprecaten.
Jörg W. schrieb:> mh schrieb:>> dass SBI read-modify-write macht?>> Daher steht da wohl auch "unlike most other AVRs". Er schreibt nur> nicht, in wessen Datenblatt das so ist.>> "most other AVRs" machen offensichtlich r-m-w, aber eben dieser (oder> diese Familie) nicht.
Alle neueren AVR machen sbi/cbi ohne RMW, z.B. ATmega644, xmega, ...
Das ist z.B. wichtig, wenn man mit den PINx Register das Bit im PORTx
togglen möchte. Ein RMW auf PINx toggled u.U. alle Ausgänge, bei denen
derzeit '1' gelesen werden kann.
Es gab vor Jahren auch in Simulavr schon mal was dazu:
https://lists.nongnu.org/archive/html/simulavr-devel/2017-06/msg00017.html
Jörg W. schrieb:> Ja, aber jemanden daran hindern zu wollen, dass er Unsinn verzapft (wie> eben UDR +=1 oder UDR |= 2) sollte nicht die Aufgabe eines> Standardkommittees sein. ;-)
Es sollte aber zumindest definiert sein, ob nun kein oder ein oder zwei
Zugriffe auf das Register passieren, und ob das dann Schreib- oder
Lesezugriffe sind.
Oliver
Jörg W. schrieb:> Es kann doch nicht Aufgabe des Standards sein, die Programmierer vor> selbst produziertem Unfug zu erretten.
Bei C natürlich nicht. Oder gerade. C++ sollte ja was besseres werden,
hat nicht ganz geklappt. Also hat man nur zu dem Zweck komplett neue
Sprachen konstruiert. Will keiner haben...
Max schrieb:> Das ist z.B. wichtig, wenn man mit den PINx Register das Bit im PORTx> togglen möchte.
Wenn man dafür ein SBI nimmt, ist das grober Unfug. Dafür genügt vollauf
eine simple Zuweisung der entsprechenden Bits, also ein OUT.
Noch lustiger wäre es, CBI auf so ein Register anzuwenden … was genau
sollte dann passieren?
Jörg W. schrieb:> Max schrieb:>> Das ist z.B. wichtig, wenn man mit den PINx Register das Bit im PORTx>> togglen möchte.>> Wenn man dafür ein SBI nimmt, ist das grober Unfug. Dafür genügt vollauf> eine simple Zuweisung der entsprechenden Bits, also ein OUT.
Wenn du z.B. nur ein einzelnen Bit togglen möchtest, bräuchtest ein
freies Register, ldi, out. Oder du nimmst halt einfach sbi. Steht m.W.
auch so als Beispiel im m644 Datenblatt.
> Noch lustiger wäre es, CBI auf so ein Register anzuwenden … was genau> sollte dann passieren?
cbi gibt in dem Fall keinen Sinn und es würde nichts passieren, weil die
toggle-Funktionalität des PINx nur bei '1' einen Effekt hat.
Hallo,
@Yalu: das ist genau die Frage die ich seit gestern stelle und keine
Antwort darauf bekomme. Bin gespannt ob jetzt jemand darauf reagiert.
Übrigens gibt sich der Compiler mit der Langschreibweise zufrieden.
Jörg W. schrieb:> Die Antwort ist: der Wert von b ist, was auch immer aus a ausgelesen> werden kann nach dieser Operation.
Und da bist du dir sicher? Ich würd sagen, das ist nicht garantiert.
Der Standard sagt zu Prefix increment and decrement operators
1
The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation. The expression ++E is
2
equivalent to (E+=1) . See the discussions of additive operators and compound assignment for information on constraints, types, side effects, and conversions and the effects of operations on pointers.
Das "equivalent to (E+=1)" und "See [...] compound assignment for
information on constraints" geben dem Compiler zwei Möglichkeiten. Der
Compiler muss den evtl. geänderten Wert von a nicht neu auslesen.
Jörg W. schrieb:> Es kann doch nicht Aufgabe des Standards sein, die Programmierer vor> selbst produziertem Unfug zu erretten.
Nein, aber es sollte das Ziel sein, einen selbskonsistenten eindeutigen
Standard zu schreiben. Und wie du hoffentlich siehst, sind die Dinge
nicht so klar wie du angenommen hast.
Max schrieb:> Jörg W. schrieb:>> Max schrieb:>>> Das ist z.B. wichtig, wenn man mit den PINx Register das Bit im PORTx>>> togglen möchte.>>>> Wenn man dafür ein SBI nimmt, ist das grober Unfug. Dafür genügt vollauf>> eine simple Zuweisung der entsprechenden Bits, also ein OUT.>> Wenn du z.B. nur ein einzelnen Bit togglen möchtest, bräuchtest ein> freies Register, ldi, out. Oder du nimmst halt einfach sbi. Steht m.W.> auch so als Beispiel im m644 Datenblatt.http://ww1.microchip.com/downloads/en/DeviceDoc/doc2593.pdf
[code]
12.2.2 Toggling the Pin
Writing a logic one to PINxn toggles the value of PORTxn, independent on
the value of DDRxn.Note that the SBI instruction can be used to toggle
one single bit in a port.
[code]
Jörg W. schrieb:> mh schrieb:>> dass SBI read-modify-write macht?>> Daher steht da wohl auch "unlike most other AVRs". Er schreibt nur> nicht, in wessen Datenblatt das so ist.>> "most other AVRs" machen offensichtlich r-m-w, aber eben dieser (oder> diese Familie) nicht.
Das steht in so gut wie allen Datenblättern von so gut wie allen AVRs.
Ausnahme sind die Uralt-Typen Mega8/16/32/64/128, und noch in paar aus
der Zeit.
Das „unlike most other“ hat da mal irgend ein Atmel-Ingenieur in das
Datenblatt des ersten AVRs geschrieben, der mit Single Bit sbi kam, und
da alle AVR-Datenblätter durch copy-Paste entstanden sind, steht’s halt
so seit Jahren in allen Datenblättern, auch wenn es schon lange nicht
mehr zutrifft.
Oliver
Hallo,
ganz praktisches Bsp. Ersteres kompliert ohne Warnung.
1
#include<avr/io.h>
2
3
uint8_tcount;
4
5
intmain(void)
6
{
7
while(1)
8
{
9
++count;
10
}
11
}
Zweiteres kompiliert mit Warnung.
Warning '++' expression of 'volatile'-qualified type is deprecated
[-Wvolatile]
1
#include<avr/io.h>
2
3
volatileuint8_tcount;
4
5
intmain(void)
6
{
7
while(1)
8
{
9
++count;
10
}
11
}
'volatile' sagt dem Compiler das er die Variable count nicht optimieren
darf. An der eigentlichen Operation ++count wurde nichts geändert. Und
jetzt stellt mal einen Zusammenhang zwischen der
Optimierungsverhinderung und dem Inkrement her. Das funktioniert erst
wieder wenn man das Inkrement in lang schreibt.
1
#include<avr/io.h>
2
3
volatileuint8_tcount;
4
5
intmain(void)
6
{
7
while(1)
8
{
9
count=count+1;
10
}
11
}
Das heißt man hat am vorher angemeckerten 'volatile' nichts geändert und
korrigiert im Code an völlig anderer Stelle. Leute, dass ist völlig ohne
jede Logik an der Praxis vorbei. Und dann kommen die noch mit 'load' und
'store' um die Ecke als die Lösung aller Probleme. Mal ehrlich, da kann
man nur mit dem Kopf schütteln.
Yalu X. schrieb:> Auch ich versuche gerade, die Problematik von Compound-Assignments in> Verbindung mit volatile zu verstehen, allerdings bisher ohne Erfolg.>> In allen Artikeln, die ich bisher darüber gelesen habe, steht sinngemäß,> die Semantik sei unklar bzw. mehrdeutig. Diese Aussage an sich ist für> mich aber zu abstrakt, um ein reales Problem darin zu erkennen.
Wenn ein compound assignment zu einem RMW gemacht wird, kann es ein race
(z.B. Interrupt oder HW, die den Registerwert ändert, ...) geben. Wird
daraus z.B. ein sbi ist es atomar und kein race. Auch bei AVR kann ein
"|= 1" als RMW oder als sbi umgesetzt werden, denn sbi/cbi gehen nur für
die ersten paar Register, nicht bei allen.
Auf (C++-)Sprachebene kann man das nicht unterscheiden, denn das macht
ja erst der spezifische Optimizer. Daher kann ich mir vorstellen, dass
man solche Mehrdeutigkeiten aus der Sprachdefinition entfernen möchte.
Anderenfalls müsste man aus dem Optimizer heraus eine Warnung
generieren, wenn ein compound assignment so übersetzt wird/werden muss,
dass es Seiteneffekte haben kann und man stattdessen besser explizit die
zwei Lesezugriffe ausschreiben müsste. Aber das ist ja auch irgendwie
blöd.
Veit D. schrieb:> 'volatile' sagt dem Compiler das er die Variable count nicht optimieren> darf.
Ahh der gute alte Mythos ... was genau darf der Conpiler nicht
optimieren?
Veit D. schrieb:> uint8_t count;>> int main(void)> {> while (1)> {> ++count;> }> }
Das ist in C++ undefined behaviour.
mh schrieb:> Das ist in C++ undefined behaviour.
Die Diskussion darüber könnte allerdings identisch zu der zu volatile
ablaufen ;)
Nur, daß die Abschaffung der meisten volatile-Fälle erst in 3-6 Jahren
droht, die UB-Schleife aber heute schon so im Standard steht.
Veit D. schrieb:> Das heißt man hat am vorher angemeckerten 'volatile' nichts geändert und> korrigiert im Code an völlig anderer Stelle.
Na ja, daß nicht volatile an sich angemeckert wird, sondern die
Benutzung des Inkremement-Operators auf eine volatile Variable, sollte
einem schon klar sein. Sonst ist die Diskussion ziemlich sinnlos.
Oliver
Yalu X. schrieb:> Die Leute von Normungsgremium behaupten nun, die Semantik der obigen> Anweisung sei mehrdeutig.
Ist das jetzt eine Vermutung von dir, oder hat jemand offiziell gesagt,
dass dieser einfache Ausdruck mehrdeutigt und damit ein Grund für die
Änderung ist?
Ich bin bis jetzt davon ausgegangen, dass der ganze volatile Sumpf das
Problem ist, der ganz gut mit dem Satz
1
What constitutes an access to an object that has volatile-qualified type is implementation-defined.
Hallo,
ja das Inkrement wurde angemeckert. Aber nur wegen der volatile
Definition. Ohne volatile ist das Inkrement okay, was letztlich bedeutet
das es keine Mehrdeutigkeit durch die Kurschreibweise gibt. Ich weiß
nicht was daran undefiniert sein soll. Wird auch nicht angemeckert.
Wegen volatile. Es weißt den Compiler an bei jedem Zugriff erneut im
Speicher nachzuschauen und es nicht im besseren Register vorzuhalten.
Der Compiler kann nicht wissen wo der Programmierer eine Variable
verändern lässt. Zum Bsp. in einer ISR. Deswegen verwendet man ja
'volatile'. Was sonst?
Ihr merkt ja selbst das alles verkompliziert wurde. Nach all dem
Durcheinander ist die Kurzschreibweise mit Nicht volatile Variablen
erlaubt und mit volatile nur die Langschreibweise. Ihr müßt einsehen das
ist ziemlicher Mist und einfach nur Kaos.
Für das Inkrement alleine gibts demnach keine Mehrdeutigkeiten, was auch
immer da gesehen wird. Und volatile sagt nur hole immer frische Werte.
Ich sehe nachwievor kein einziges Problem. Tut mir leid.
mh schrieb:> Ich bin bis jetzt davon ausgegangen, dass der ganze volatile Sumpf das> Problem ist, der ganz gut mit dem Satz>
1
> What constitutes an access to an object that has volatile-qualified type
2
> is implementation-defined.
3
>
> aus dem C++ Standard zusammengefasst wird.
Genau, dann müssen sie die Implementierung ausbessern aber nicht dem
Programmierer solchen Mist aufhalsen. Das ist völlig falsche Welt.
Max schrieb:> Wenn ein compound assignment zu einem RMW gemacht wird, kann es ein race> (z.B. Interrupt oder HW, die den Registerwert ändert, ...) geben. Wird> daraus z.B. ein sbi ist es atomar und kein race.
D.h. es ist beim Compound-Assignment nicht klar, ob es atomar ist oder
nicht.
Aber ist das wirklich ein Problem?
- Um portabel zu bleiben, muss ich davon ausgehen, dass es nicht
atomar ist. Wenn es wieder Erwarten dennoch atomar ist, entsteht
dadurch kein Schaden.
- Es gibt noch viele andere Konstrukte, die je nach Architektur atomar
sein können oder auch nicht. Ein Beispiel wäre eine gewöhnliche
int-Zuweisung: Sie ist auf 32-Bit-Prozessoren i.Allg. atomar, nicht
aber auf 8-Bit-Prozessoren. Konsequenterweise müssten sämtliche
Zuweisungen an volatile-Variablen (egal ob Compound oder nicht)
verboten werden.
Ich danke dir für deine Antwort, aber irgendwie hat sie mich noch nicht
so richtig erleuchtet :)
mh schrieb:> Yalu X. schrieb:>> Die Leute von Normungsgremium behaupten nun, die Semantik der obigen>> Anweisung sei mehrdeutig.>> Ist das jetzt eine Vermutung von dir, oder hat jemand offiziell gesagt,> dass dieser einfache Ausdruck mehrdeutigt und damit ein Grund für die> Änderung ist?
Ich habe es so verstanden, dass Compound-Assignments an eine volatile-
Variable mehrdeutig sein können. Ob das auch für einfache Fälle wie in
meinem Beispiel gilt oder nicht, wurde in den von mir gelesenen Artikeln
nicht explizit geschrieben.
Die Deprecation der volatile-Compound-Assignments betrifft jedenfalls
auch solche einfachen Fälle, sonst wären im Standard entsprechende
Ausnahmen spezifiziert.
Wenn mein Beispiel zu einfach war und damit zu keinen Problemen führen
kann, wäre ich an einem komplexeren Beispiel interessiert, das die
Problematik besser aufzeigt.
Hallo,
wird das Thema jetzt mit atomaren Zugriff vermischt? Hat mit dem Problem
nichts zu tun. Das muss der Programmierer festlegen welche Variable mit
'atomic' Schutz bearbeitet wird. Ansonsten reden nämlich alle mit 3
verschiedenen Themen (volatile, Inkrement und atomar) durcheinander und
aneinander vorbei.
Oliver S. schrieb:> Die Diskussion darüber könnte allerdings identisch zu der zu volatile> ablaufen ;)
Die hatten wir hier erst vor kurzem. Da gabs auch ne kleine Excurion in
Volatile Land.
Veit D. schrieb:> Ich weiß> nicht was daran undefiniert sein soll. Wird auch nicht angemeckert.
Dein Wissen ändert an der Tatsache allerdings nichts.
Veit D. schrieb:> Wegen volatile. Es weißt den Compiler an bei jedem Zugriff erneut im> Speicher nachzuschauen und es nicht im besseren Register vorzuhalten.> Der Compiler kann nicht wissen wo der Programmierer eine Variable> verändern lässt. Zum Bsp. in einer ISR. Deswegen verwendet man ja> 'volatile'.
Nö.
Veit D. schrieb:> Was sonst?
Ich habe keine Lust das nochmal durchzukauen. Du kannst hier im Forum
oder im restlichen Internet suchen, da sollten sich etwas finden lassen.
Alternativ kannst du den Standard lesen.
Veit D. schrieb:> Genau, dann müssen sie die Implementierung ausbessern aber nicht dem> Programmierer solchen Mist aufhalsen. Das ist völlig falsche Welt.
Das wird doch gerade gemacht.
Yalu X. schrieb:> Die Deprecation der volatile-Compound-Assignments betrifft jedenfalls> auch solche einfachen Fälle, sonst wären im Standard entsprechende> Ausnahmen spezifiziert.
Das wäre aber wirklich unsinn, wenn sie nach Komplexität der Anwendung
deprecated werden ;-)
Yalu X. schrieb:> Wenn mein Beispiel zu einfach war und damit zu keinen Problemen führen> kann, wäre ich an einem komplexeren Beispiel interessiert, das die> Problematik besser aufzeigt.
Für C++ kann ich das nicht wirklich. An den paar Stellen an denen ich
Register lese und schreibe, mache ich auch genau das, eindeutig und ohne
jede Komplexität. Jede andere Stelle, an der volatile vorkommt ist nen
Bug und sollte vermutlich durch atomics ersetzt werden. Für C hab ich ja
genug geschrieben.
Yalu X. schrieb:> - Um portabel zu bleiben, muss ich davon ausgehen, dass es nicht> atomar ist. Wenn es wieder Erwarten dennoch atomar ist, entsteht> dadurch kein Schaden.
Das sollte man allein schon deswegen annehmen, um nicht später durch
Compileroptimierungen durchgebumst zu werden. Überall nicht-atomische*,
unsynchronisierte Lese-/Schreibzugriffe hinzuballern schreit ja förmlich
danach.
* und zwar atomisch in der abstrakten Maschine, Implementationsdetails
sind völlig irrelevant!
Hallo,
Iso Draft N4606, was neueres habe ich über www.open-st.org nicht
gefunden bzw. wurde mir das angeboten.
Seite 165
Note: volatile is a hint to the implementation to avoid aggressive
optimization involving the object becausethe value of the object might
be changed by means undetectable by an implementation. Furthermore,
forsome implementations,volatilemight indicate that special hardware
instructions are required to access theobject. See 1.9 for detailed
semantics. In general, the semantics ofvolatileare intended to be the
same inC++as they are in C.— end note]
Nichts anderes habe ich Gebetsmühlenartig geschrieben. 'volatile'
erzwingt einen Speicherzugriff.
Andere Quelle:
Auszug C++11 Stroustrup
1
41.4 volatile
2
Der Spezifizierer volatile zeigt an, dass ein Objekt durch etwas außerhalb des steuernden
3
Threads modifiziert werden kann. Zum Beispiel:
1
volatileconstlongclock_register;// wird von der Hardware-Uhr aktualisiert
1
Prinzipiell weist volatile den Compiler an, keine scheinbar redundanten Lese- und
2
Schreiboperationen wegzuoptimieren. Zum Beispiel:
1
autot1{clock_register};
2
// ... clock_register wird hier nicht verwendet ...
3
autot2{clock_register};
1
Wäre clock_register nicht als volatile deklariert, könnte der Compiler durchaus eine der
2
Leseoperationen eliminieren und t1==t2 annehmen.
3
Verzichten Sie am besten auf volatile, außer in systemnahem Code, der direkt auf die
4
Hardware zugreifen muss.
5
Nehmen Sie auch nicht an, dass volatile im Speichermodell eine besondere Bedeutung
6
besitzt. Es hat keine. Es ist auch kein Synchronisierungsmechanismus – wie in manchen
7
neueren Sprachen. Verwenden Sie atomic (§ 41.3), mutex (§ 42.3.1) oder condition_variable
8
(§ 42.3.4), wenn Sie Synchronisierung benötigen.
Hier könnte man verstehen volatile gar nicht mehr verwenden zu müssen.
Kann aber nicht sein. atomic sorgt nur dafür das ohne Unterbrechung auf
eine Variable zugegriffen werden kann damit sie während des Zugriffs
nicht verfälscht wird. Denn sonst könnte unter atomic Schutz ohne
volatile auf einen alten Wert zugegriffen werden. Das ist Irre führend.
Veit D. schrieb:> Nichts anderes habe ich Gebetsmühlenartig geschrieben. 'volatile'> erzwingt einen Speicherzugriff.
Du hast im ganzen Standard nur eine "Note" mit einem "Hint" gefunden.
Mal davon abgesehen, dass da "avoid aggressive optimization" steht und
nicht "darf nicht optimieren". An der Stelle steht keine klare Regel,
was der Compiler darf und was nicht.
Veit D. schrieb:> atomic sorgt nur dafür das ohne Unterbrechung auf> eine Variable zugegriffen werden kann damit sie während des Zugriffs> nicht verfälscht wird.
Uhhhh da hast du dich aber nicht sehr gründlich über atomics informiert.
Um nochmal auf das a = b = c von vorhin zurück zu kommen.
Max schrieb:> Wenn du z.B. nur ein einzelnen Bit togglen möchtest, bräuchtest ein> freies Register, ldi, out. Oder du nimmst halt einfach sbi.
Du kannst genausogut gleich ein OUT nehmen. Das hat die gleichen
Operanden wie SBI, würde allerdings einen größeren Zieladressbereich
unterstützen als SBI (was für PINx jedoch unwichtig ist). Es gibt da gar
keinen Grund für SBI an dieser Stelle – auch wenn das im Datenblatt
genauso zulässig ist.
Max schrieb:> Wenn ein compound assignment zu einem RMW gemacht wird, kann es ein race> (z.B. Interrupt oder HW, die den Registerwert ändert, ...) geben.
Ja, und? Niemand hat je garantiert, dass da was atomic wäre. Das ist
aber völlig unabhängig davon, ob man nun für die Operation einen
compound operator nimmt oder die "Langform" x = x <op> y.
Insofern ist die deprecation der compound operators zugunsten der
Langform in keiner Weise nachvollziehbar – und wie ich oben schon
schrieb, erst recht nicht unter dem Gesichtspunkt, dass die Langform ja
explizit den lvalue zweimal bewertet, während der compound operator es
garantiert nur einmal macht. Unabhängig davon, zu welchen Opcodes der
Salat am Ende compiliert.
Man wird halt in diesem Bereich unmöglich auf der Ebene einer abstrakten
Sprachdefinition sämtliche Unwägbarkeiten beseitigen können. Es wäre
dann allemal sinnvoller gewesen, die verbleibenden Unwägbarkeiten als
"implementation-defined" zu deklarieren. Dann hätte wenigstens jede
konkrete Implementierung eine Chance gehabt, das für sich exakter
festzulegen, als es ein allgemeiner Sprachstandard kann.
Jörg W. schrieb:> Max schrieb:>> Wenn du z.B. nur ein einzelnen Bit togglen möchtest, bräuchtest ein>> freies Register, ldi, out. Oder du nimmst halt einfach sbi.>> Du kannst genausogut gleich ein OUT nehmen. Das hat die gleichen> Operanden wie SBI, würde allerdings einen größeren Zieladressbereich> unterstützen als SBI (was für PINx jedoch unwichtig ist). Es gibt da gar> keinen Grund für SBI an dieser Stelle – auch wenn das im Datenblatt> genauso zulässig ist.
Aber OUT kann doch keine Konstante/Bitmaske in das I/O Register
schieben?! D.h. man muss ein ALU Register opfern/clobbern, was man bei
bitadressierten SBI/CBI nicht muss.
Hallo,
@ mh:
deine nichts sagenden Antworten mir gegenüber kannste dir schenken, wenn
nichts besseres kommt. Den ISO Standard kaufe ich auf deren Seite
sicherlich nicht. Im Draft habe ich gesucht und ja nichts besseres
gefunden. Auch übern Index nicht. Stroustrup habe ich auch zitiert.
Darauf gehst du gar nicht ein.
Also zeig mir besseres oder lass es sein.
Ich habe mir eben die erste Version der P1152 durchgelesen, die eine
ausführlichere Begründung enthält:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1152r0.html
Spontan fallen mir nur wenige Beispiele mit volatile und
++/--/-=/+=//=/*=/%= ein. Und wenn, dann sind es seltene Sonderfälle,
die man leicht explizit schreiben könnte (a = a + 1).
Ätzend ist das ganze IMHO wirklich nur bei Bitoperationen |=/&=/~= und
evtl. %= mit Zweierpotenz (da äquivalent zu &=).
Man kann manchmal (wenn das Ursprungsbit 0 ist) natürlich auch += statt
|= verwenden, das hat aber eine andere Semantik und sollte IMHO zurecht
vom Compiler moniert werden.
Mit Ausnahme der Compund-Bitoperationen könnte ich mit einer
expliziteren/verboseren Schreibweise gut leben.
Max schrieb:> Mit Ausnahme der Compund-Bitoperationen könnte ich mit einer> expliziteren/verboseren Schreibweise gut leben.
Vielleicht bleiben garnicht so viele solche Fälle übrig, wenn man
volatile gezielter, also sparsamer, nutzen könnte. Ein einfacher
GPIO-Port braucht volatile sicher beim Input-Register, aber sicher nicht
beim DDR oder Pull-Register.
Max schrieb:> Mit Ausnahme der Compund-Bitoperationen könnte ich mit einer> expliziteren/verboseren Schreibweise gut leben.
Ja, das sind genau die, die einen großen Teil der
Lowlevel-Funktionalität direkt oberhalb der Hardware ausmachen
(zumindest auf manchen Hardware-Implementierungen – andere haben
explizite Bitset- und Bitclear-Register, da ist das egal). Von genau
dieser Ebene scheinen die Standardiseure einfach mal viel zu weit
abgehoben zu sein.
Selbst für Dinge wie += ist es aber Kokolorus. Ich sehe keinen Grund,
warum bspw. ein OCR1A = OCR1A + 5 nun weniger problematisch sein sollte
als ein OCR1A += 5 (um mal ein Beispiel zu nennen, bei denen += durchaus
Sinn hätte).
Veit D. schrieb:> @ mh:> deine nichts sagenden Antworten mir gegenüber kannste dir schenken, wenn> nichts besseres kommt. Den ISO Standard kaufe ich auf deren Seite> sicherlich nicht. Im Draft habe ich gesucht und ja nichts besseres> gefunden.
Vielleicht solltest du den Standard (draft reicht) einfach mal lesen.
Aus dem (meiner Meinung nach) wichtigsten Kapitel des Standards:
http://eel.is/c++draft/intro.abstract#6
1
4 General principles
2
4.1 Implementation compliance
3
4.1.1 Abstract machine
4
5
Accesses through volatile glvalues are evaluated strictly according to the rules of the abstract machine.
The semantics of an access through a volatile glvalue are implementation-defined.
Um zu zeigen, dass ich mir die Interpretation nicht aus der Nase ziehe
und es andere gibt (neben dem Std-Committee und den ganzen Blogs mit
"dont use volatile"), die die Probleme sehen, weise ich noch auf die
autoconf Dokumentation hin, die sich zwar hauptsächlich auf c bezieht,
aber teilweise auf c++ übertragbar ist:
https://www.gnu.org/software/autoconf/manual/autoconf-2.61/html_node/Volatile-Objects.html
1
The keyword volatile is often misunderstood in portable code. Its use inhibits some memory-access optimizations, but programmers often wish that it had a different meaning than it actually does.
2
3
volatile was designed for code that accesses special objects like memory-mapped device registers whose contents spontaneously change. Such code is inherently low-level, and it is difficult to specify portably what volatile means in these cases. The C standard says, “What constitutes an access to an object that has volatile-qualified type is implementation-defined,” so in theory each implementation is supposed to fill in the gap by documenting what volatile means for that implementation. In practice, though, this documentation is usually absent or incomplete.
4
5
[...]
6
7
Programmers often wish that volatile meant “Perform the memory access here and now, without merging several memory accesses, without changing the memory word size, and without reordering.” But the C standard does not require this. For objects defined with a volatile type, accesses must be done before the next sequence point; but otherwise merging, reordering, and word-size change is allowed. Worse, it is not clear from the standard whether volatile lvalues provide more guarantees in general than nonvolatile lvalues, if the underlying objects are ordinary.
mh schrieb:> In practice, though, this documentation is usually absent or incomplete.
Das ist doch aber kein Argument, deshalb volatile mehr oder weniger
verbieten zu wollen.
Es ist an dieser Stelle schlicht und ergreifend
"implementation-defined", nicht mehr, aber auch nicht weniger. Wenn die
Implementierung das nicht dokumentiert, dann ist das ein Mangel der
Implementierung, nicht des Standards.
Jörg W. schrieb:> mh schrieb:>> In practice, though, this documentation is usually absent or incomplete.>> Das ist doch aber kein Argument, deshalb volatile mehr oder weniger> verbieten zu wollen.
Nein ist es nicht. Aber warum darf das Problem nicht durch den Standard
gelöst werden? (Abgesehen davon, dass du hier anscheinend keine Problem
siehst.)
Jörg W. schrieb:> Es ist an dieser Stelle schlicht und ergreifend> "implementation-defined", nicht mehr, aber auch nicht weniger. Wenn die> Implementierung das nicht dokumentiert, dann ist das ein Mangel der> Implementierung, nicht des Standards.
Es funktioniert aber offensichtlich nicht, also sollte man etwas ändern.
Der Standard ist meiner Meinung nach die richtige Wahl dafür.
Jörg W. schrieb:> Max schrieb:>> Mit Ausnahme der Compund-Bitoperationen könnte ich mit einer>> expliziteren/verboseren Schreibweise gut leben.>> Ja, das sind genau die, die einen großen Teil der> Lowlevel-Funktionalität direkt oberhalb der Hardware ausmachen> (zumindest auf manchen Hardware-Implementierungen – andere haben> explizite Bitset- und Bitclear-Register, da ist das egal). Von genau> dieser Ebene scheinen die Standardiseure einfach mal viel zu weit> abgehoben zu sein.
Darauf wollte ich hinaus und stimme dir zu.
> Selbst für Dinge wie += ist es aber Kokolorus. Ich sehe keinen Grund,> warum bspw. ein OCR1A = OCR1A + 5 nun weniger problematisch sein sollte> als ein OCR1A += 5 (um mal ein Beispiel zu nennen, bei denen += durchaus> Sinn hätte).
Danke für das Beispiel. Mit der neuen Schreibweise macht man explizit,
dass es zwei Registerzugriffe sind und es sich anscheinend um
"besonderen" (volatile) Speicher handelt. Das sind genau die seltenen
Fälle, mit denen ich gut leben könnte. Dafür fliegt volatile an einigen
anderen Stellen raus (Methoden, Bitfelder, gemischte structs, ...).
Hallo,
Max und mh. Ich lese mir das alles durch.
Danke erstmal allen die am Ball geblieben sind und ihr Wissen und
Meinung kundt getan haben. Benötige nur erstmal etwas Abstand zum Thema.
Hier prallen verschiedene Ansichten und unterschiedliches Wissen
aufeinander. Da muss man erstmal cool bleiben und zurückfahren. Ich lese
jedoch weiter mit. Das Thema ist und bleibt auf jeden Fall interessant.
Jörg W. schrieb:> Das ist doch aber kein Argument, deshalb volatile mehr oder weniger> verbieten zu wollen.
Das wird es ja gar nicht, Die Nutzung wird nur radikal auf seine
ursprüngliche Grundfunktion zusammengestrichen, nämlich die Nutzung bei
load und store von Variablen.
Und wie gesagt, die tatsächliche Umstzung all dieser Einschränkungen
scheint auch noch nicht endgültig entschieden zu sein.
Der Autor des PR ist anscheinend Compilerbauer, durch dessen Brille ist
der radikale Ansatz natürlich die beste Lösung. Bis C++23 oder auch
C++26 das dann wirklich umsetzten, wird hoffentlich die Anwendersicht
auch noch eine Rolle spielen.
Bis dahin kann man die deprecated-Warnung im Compiler einfach
abschalten, wenn man sich sicher ist, daß das keine tatsächlichen
Falschverwendungen von volatile verdeckt.
Oliver
Bauform B. schrieb:> Ein einfacher> GPIO-Port braucht volatile sicher beim Input-Register, aber sicher nicht> beim DDR oder Pull-Register.
Doch, schon, weil volatile nicht nur garantiert, daß der Zugriff
stattfindet, sondern auch, daß die Reihenfolge relativ zu anderen
volatile-Zugriffen nicht verändert wird. Man möchte ja sicherlich die
Datenrichtung vor dem Datenzugriff konfiguriert haben.
Max schrieb:> Mit der neuen Schreibweise macht man explizit, dass es zwei> Registerzugriffe sind
Mit dem gleichen Argument könnte man allerdings die Verbundoperatoren
gleich komplett aus der Sprache kicken, denn schließlich "verschleiern"
sie, dass auf das entsprechende Objekt zweimal zugegriffen wird – stets,
nicht nur bei volatile.
Jörg W. schrieb:> denn schließlich "verschleiern"> sie, dass auf das entsprechende Objekt zweimal zugegriffen wird – stets,
Das spielt bei nonvolatile-Zugriffen aber keine Rolle.
Zugriffe können da eh beliebig weg- und hinzuoptimiert werden, wenn sich
die Logik des Programmes dadurch nicht ändert.
Veit D. schrieb:> Auszug C++11 Stroustrup41.4 volatile> Der Spezifizierer volatile zeigt an, dass ein Objekt durch etwas> außerhalb des steuernden> Threads modifiziert werden kann. Zum Beispiel:> volatile const long clock_register; // wird von der Hardware-Uhr> aktualisiert> Prinzipiell weist volatile den Compiler an, keine scheinbar redundanten> Lese- und> Schreiboperationen wegzuoptimieren. Zum Beispiel:> auto t1 {clock_register};> // ... clock_register wird hier nicht verwendet ...> auto t2 {clock_register};
Angenommen, man hätte wirklich sowas:
1
longstart=clock_register;
2
for(inti=0;i<100;i++)noop;
3
longend=clock_register;
4
longdiff=end-start;
Dann dürfte der Compiler das aber doch optimieren zu:
1
for(inti=0;i<100;i++)noop;
2
longstart=clock_register;
3
longend=clock_register;
4
longdiff=end-start;
Oder? Da bräuchte es doch noch eine Memory barrier, damit das geht?
DPA schrieb:> Oder? Da bräuchte es doch noch eine Memory barrier, damit das geht?
Der Compiler muß die Reihenfolge von volatile-Zugriffen nur relativ zu
anderen volatile-Zugriffen einhalten. Non-volatile-Zugriffe darf er
relativ zu volatile-Zugriffen umordnen. Das ist ein wesentlicher Grud,
wieso volatile alleine nicht zur Synchronisierung geeignet ist.
Aus Compiler-Sicht braucht es keine Memory-Barrier, eine
Compiler-Barrier reicht. Oder Du machst den noop als "asm volatile", das
geht auch.
Die Memory-Barrier brauchst Du, wenn die CPU out-of-order-execution
machen könnte. Darauf hat der Compiler ja keinen Einfluß mehr. Deswegen
sind in Mutexes automatisch memory barriers enthalten.
Nop schrieb:> Bauform B. schrieb:> Ein einfacher> GPIO-Port braucht volatile sicher beim Input-Register, aber sicher nicht> beim DDR oder Pull-Register.>> Doch, schon, weil volatile nicht nur garantiert, daß der Zugriff> stattfindet, sondern auch, daß die Reihenfolge relativ zu anderen> volatile-Zugriffen nicht verändert wird. Man möchte ja sicherlich die> Datenrichtung vor dem Datenzugriff konfiguriert haben.
Schiet; aber das ist ein gutes Beispiel, dass doch jede Menge schief
gehen kann, volatile ist eben nicht so trivial. Deshalb bin ich dafür,
dass der gcc noch viel mehr Warnungen produziert. Mit #pragma
gcc-diagnostic (oder so) kann man ja eine bestimmte Warnung gezielt pro
Statement abschalten, dafür fehlt nur eine kürzere Schreibweise.
Hallo,
also das übersetzen solcher Texte ist mühsam. Es gibt viel zu viel
hätte, könnte, vielleicht. Zusätzlich kommt erschwerend hinzu das man
deswegen zwischem dem C++ Standard mit seinem typischen Satz "ist
Implementierungsabhängig" und der wirklichen gcc Implementierung
unterscheiden muss. Wer soll da noch durchblicken?
Ich kann am Schlüsselwort 'volatile' noch immer nichts schlechtes
erkennen. Wenn es benötigt wird muss man es verwenden. Steht auch im
Text. Ich kann nichts anderes ableiten.
Zudem ich immer noch nicht weiß was an der Kurzschreibweise ++var falsch
sein soll. Ist doch vollkommen egal ob var dabei mit 'volatile'
gekennzeichnet ist oder nicht. Im schlimmsten Fall habe ich einen
Performance Verlust. Die Kurzschreibweise hat ja mit dem Typ Qualifier
'volatile' nichts zu tun.
Wenn es dem Compiler stört, dann soll er gefälligst intern daraus var =
var + 1 machen. Was anderes beabsichtigt der Programmierer sowieso
nicht.
Desweiteren hat volatile und atomar ebenfalls nichts miteinander zu tun.
Es muss nur oft gemeinsam verwendet werden. Beides soll nun scheinbar
mit volatile_load<T> and volatile_store<T> kombiniert werden. Ich kann
jedoch nicht entnehmen ob dann der Typ Qualifier 'volatile' bei der
Variablendeklaration wegfallen soll. Ich vermute es nur.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1382r1.pdf
Ich kann jedoch auch hier nicht entnehmen ob damit die atomic Blöcke
wegfallen?
1
volatileintcount;
2
intupdated;
3
4
intmain(void)
5
{
6
while(1)
7
{
8
// statt ...
9
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
10
{
11
updated=count;
12
}
13
14
// Soll daraus das werden?
15
volatile_store(updated,volatile_load(count));
16
}
17
}
18
19
ISR(TIMER1_COMPA_vect)
20
{
21
// aus
22
++count;
23
// wird
24
count=count+1;
25
}
Zur Zeit kann ich für mich erstmal nur aus all dem ableiten, dass ich
die Warnung abschalte und für eigenen Code Zähneknirschend die
Langschreibweise für Inkrements verwende. Dann müßte ich aus dem
Gröbsten raus sein.
Veit D. schrieb:> Wenn es dem Compiler stört, dann soll er gefälligst intern daraus var => var + 1 machen. Was anderes beabsichtigt der Programmierer sowieso> nicht.
Das ist deine persönliche und private Annahme.
Wissen die Compilerbauer das auch?
Oliver S. schrieb:> Nach dem Paper hier wird aber „strongly recommended“, die Umsetzung auf> C++26 zu verschieben.
Meine Glaskugel sagt mir, dass 2026 nur noch eine kleine Elite geistig
in der Lage sein wird, in C++ zu programmieren. Diese Elite wird im
Wesentlichen aus den Mitgliedern des C++-Normungsgremiums bestehen. Der
ganze Rest wird schon vorher auf Rust umgeschwenkt haben und weiterhin
produktiv arbeiten ;-)
Yalu X. schrieb:> Der> ganze Rest wird schon vorher auf Rust umgeschwenkt haben und weiterhin> produktiv arbeiten ;-)
Und Rust verwendet auch volatile_load() und volatile_store().
Hallo,
also je mehr ich mich damit beschäftige umso sinnfreier wird die
Warnung. Denn der Compiler macht in allen 3 Fällen exakt das Gleiche
daraus. Also wissen die Compilerbauer doch was sie tun und was der
Programmierer möchte. Umso unverständlicher wird die Warnung. Habe alle
3 Varianten vom Inkrement mit volatile im asmdump angeschaut. In
Assemblercodes sind exakt gleich. Also wo genau ist nun das Problem?
Veit D. schrieb:> Habe alle 3 Varianten vom Inkrement mit volatile im asmdump> angeschaut. In Assemblercodes sind exakt gleich.
Vielleicht ist genau das das Problem. volatile bewirkt genau garnichts
und das Komitee möchte den Programmierer darauf hinweisen. Wenn ich
statt
1
a=b;
versehentlich
1
a==b;
schreibe, ist die Warnung "statement without effect" (oder so) doch
auch berechtigt.
Hallo,
das hat jetzt nichts mit volatile zu tun. volatile verhindert nur die
Optimierung, ansonsten gebe es in dem Bsp. count überhaupt nicht mehr,
weil unbenutzt. Mir ging es um die möglichen Unterschiede der
Inkrementimplentierung die im Thread mal aufgekocht sind. Damit wäre
bewiesen das es keine gibt und die Kurzschreibweise genau das macht was
sie soll. Entgegen anderer Meinungen hier.
Das heißt wenn sich count bspw. in einer ISR verändert, muss ich count
als volatile kennzeichnen und kann in der ISR die Kurzschreibweise
verwenden. Die Warnung vom Compiler ist sinnfrei. Darum gehts im
gesamten Thread.
Die Warnung für = vs. == ist was anderes. Die ist sinnvoll.
Veit D. schrieb:> Mir ging es um die möglichen Unterschiede der> Inkrementimplentierung die im Thread mal aufgekocht sind. Damit wäre> bewiesen das es keine gibt und die Kurzschreibweise genau das macht was> sie soll. Entgegen anderer Meinungen hier.
Veit D. schrieb:> also je mehr ich mich damit beschäftige umso sinnfreier wird die> Warnung. Denn der Compiler macht in allen 3 Fällen exakt das Gleiche> daraus. Also wissen die Compilerbauer doch was sie tun und was der> Programmierer möchte. Umso unverständlicher wird die Warnung. Habe alle> 3 Varianten vom Inkrement mit volatile im asmdump angeschaut.
Für alle Prozessoren, die gcc unterstützt, im größeren Zusammenhang.
Sehr fleissig !!!
Oder anders ausgedrückt: Ausserhalb deiner (für den größten Teil der
Menschheit völlig unwichtigen) AVR-Blase sind Multiprozessor- und
Multithreadingumgebungen mit mehrstufigen Caches, komplexen
Memorymanagement, vielstufige Befehlspiplines mit
out-of-order-Bearbeitung und vielen weiteren Nettigkeiten der Standard,
und dafür wollen und müssen die Compilerbauer C++-konformen optimierten
Code liefern. Da macht ein nicht sauber definiertes volatile verdammt
viel Ärger.
Ob man tatsächlich einfach die allermeisten Nutzungen abschaffen soll,
kann man diskutieren, aber sauber definieren muß man es.
Oliver
Hallo,
wenn ich keine Tomaten auf den Augen habe macht der gcc Compiler in mh
Bsp. in allen 3 Fällen zuerst eine Addition mit b. Danach erfolgt eine
unterschiedliche "Optimierung" in der Zuweisung des Ergebnisses an a.
Ich kann da erstmal kein Problem erkennen. Das Inkrement ist jedenfalls
sauber.
Natürlich kann ich nicht alle CPUs prüfen. Ich bastel nur mit AVR rum.
Nur konnte mir bis jetzt niemand erklären was denn nun an der bis jetzt
gängigen Praxis so total falsch ist. volatile wird ja nachwievor
benötigt. Gerade wenn es um Threadsicherheit geht. Die gcc Entwickler
wollen das nur in anderer Form. Soweit okay. Was ich nicht verstehe ist,
wo der gefährliche Zusammenhang zwischen volatile und Inkrement
überhaupt herkommt und damit die Warnung? Inkrement ist das Eine,
volatile das Andere. Beides kann ich gefahrlos kombinieren. Ich weiß
nicht wie ich mein Verständnisproblem anders zum Ausdruck bringen
kann/soll.
Oliver S. schrieb:> Da macht ein nicht sauber definiertes volatile verdammt viel Ärger.
Dann soll man es sauber definieren, statt existierenden und
funktionierenden Code zu deprecaten.
Das betrifft übrigens bei weitem nicht nur AVR, sondern genauso gut ARM.
Auch dort dürften diese Szenarien recht großflächig in Benutzung sein.
Um mal fix nach einem Beispiel hier im Sourcetree zu suchen:
Veit D. schrieb:> Hallo,>> wenn ich keine Tomaten auf den Augen habe macht der gcc Compiler in mh> Bsp. in allen 3 Fällen zuerst eine Addition mit b. Danach erfolgt eine> unterschiedliche "Optimierung" in der Zuweisung des Ergebnisses an a.> Ich kann da erstmal kein Problem erkennen. Das Inkrement ist jedenfalls> sauber.
Dann hast du wohl Tomaten auf den Augen. Und es ist für dich vermutlich
vollkommen natürlich, dass beide Compiler etwas anderes machen, wenn
doch
alles so klar ist.
Veit D. schrieb:> volatile wird ja nachwievor benötigt.
Ja, allerdings nur als load und store für "besonderen Speicher" wie
Hardwareregister.
Veit D. schrieb:> Gerade wenn es um Threadsicherheit geht.
Deine Verknüfung von Thread, volatile und Sicherheit ist fehlerhaft.
Veit D. schrieb:> Die gcc Entwickler wollen das nur in anderer Form.
Die gcc Entwickler setzen um, was der Standard verlangt.
Veit D. schrieb:> Soweit okay. Was ich nicht verstehe ist,> wo der gefährliche Zusammenhang zwischen volatile und Inkrement> überhaupt herkommt und damit die Warnung? Inkrement ist das Eine,> volatile das Andere. Beides kann ich gefahrlos kombinieren. Ich weiß> nicht wie ich mein Verständnisproblem anders zum Ausdruck bringen> kann/soll.
Ich habe mittlerweile den Eindruck, dass du es nicht verstehen willst.
Jörg W. schrieb:> Dann soll man es sauber definieren, statt existierenden und> funktionierenden Code zu deprecaten.
Glaubst du ernsthaft, dass sie den Weg nicht geählt hätten, wenn es
einfacher wäre?
Jörg W. schrieb:> Das ist nun nichts mehr, wo du dich auf eine vorgebliche „AVR-Blase“> zurückziehen kannst.
Wo hat er gesagt, dass es beim ARM keine compound-Operationen gibt? Wo
zeigst du, dass es bei ARM keine Probleme gibt?
mh schrieb:> Wo zeigst du, dass es bei ARM keine Probleme gibt?
Indem besagter Code funktioniert.
Dass man immer irgendwelche pathologisch-unsinnigen Fälle konstruieren
können wird (wie oben, volatile mit mehrfacher Evaluierung auf der
rechten Seite), ist ein anderer Punkt. Ein einfacher Verbundoperator
gehört aber bislang nicht zu diesen Fällen und wird in der Praxis recht
häufig verwendet.
Meiner Meinung nach schüttet man hier das Kind mit dem Bade aus, weil
sich die Compilerhersteller Sicherheit wünschen – auf Kosten der
Anwender, die dann gefälligst umständlicheren Code zu schreiben haben.
Es gibt halt in komplexeren CPU-Umgebungen immer mehr Umstände, die sich
simpel nicht mehr immer fest in einem Sprachstandard definieren lassen
werden (siehe Caches). Dafür wird man nicht um herstellerabhängige
Erweiterungen herum kommen.
> Wo hat er gesagt, dass es beim ARM keine compound-Operationen gibt?
Die Erwähnung einer „unbedeutenden AVR-Blase“ ist entweder Unwissenheit
oder Überheblichkeit und war in diesem Zusammenhang schlicht unnötig.
Jörg W. schrieb:> Indem besagter Code funktioniert
Es wird aber nicht durch den Standard garantiert. Garantiert es der
Compiler?
Jörg W. schrieb:> Dass man immer irgendwelche pathologisch-unsinnigen Fälle konstruieren> können wird (wie oben, volatile mit mehrfacher Evaluierung auf der> rechten Seite), ist ein anderer Punkt.
Was genau meinst du damit? Falls du das hier
1
a=++b;
meinst, würde ich das zumindest für besseren Stil halten, als den von
dir gezeigten Magic Number Schrott, wenn es nicht dank volatile so
mehrdeutig wäre.
mh schrieb:> Falls du das hiera = ++b;>> meinst,
Ja, meine ich. Warum zum Geier™ will jemand auf so eine doofe Idee
kommen, auf der rechten Seite einer Zuweisung eine volatile-Operation
mit weiteren Nebeneffekten zu produzieren?
Das habe ich in realem Code bislang noch nicht gesehen – im Gegensatz
zu Verbundoperatoren, die es zuhauf gibt.
> würde ich das zumindest für besseren Stil halten, als den von> dir gezeigten Magic Number Schrott, wenn es nicht dank volatile so> mehrdeutig wäre.
Den „Magic Number Schrott“ hat STM verbrochen und liefert ihn für deren
MCUs.
Ich würde das auch nicht so schreiben. ;-)
Jörg W. schrieb:> Ja, meine ich. Warum zum Geier™ will jemand auf so eine doofe Idee> kommen, auf der rechten Seite einer Zuweisung eine volatile-Operation> mit weiteren Nebeneffekten zu produzieren?
Warum nicht, wenn es doch angeblich das gleiche ist wie
1
++b;
2
a=b;
Jörg W. schrieb:> Den „Magic Number Schrott“ hat STM verbrochen und liefert ihn für deren> MCUs.>> Ich würde das auch nicht so schreiben. ;-)
Da du es als Beispiel nutzt, musst du auch mit der Kritik leben.
mh schrieb:> Warum nicht, wenn es doch angeblich das gleiche ist wie
Weil es um Verbundoperatoren ging.
Ich sehe da keinen.
> Da du es als Beispiel nutzt, musst du auch mit der Kritik leben.
Schön. Wenn man keine Argumente weiter hat, warum Verbundoperatoren
problematisch sind, zieht man sich an der Form von deren Code hoch? Als
ob es für den Compiler ein Unterschied wäre, ob da nun im Quelltext
Hallo,
>> Die gcc Entwickler wollen das nur in anderer Form.> Die gcc Entwickler setzen um, was der Standard verlangt.
Hier habe ich gcc mit C++ Entwicklern verwechselt.
> Ich habe mittlerweile den Eindruck, dass du es nicht verstehen willst.
Ich habe einen anderen Eindruck. Ich bemühe mich redlich mein
Verständnisproblem darzustellen. Immer und immer wieder. Ich habe den
Eindruck das man mich nicht verstehen möchte. Man redet lieber drumherum
oder sagt nichts. Die Kurzantworten sind auch so eine klare Botschaft.
Andersherum erkläre ich jeden anderen jedes Problem was ich erklären
kann bis er es gelöffelt hat. Leider gibt sich bei mir niemand Mühe. Ich
dachte immer ein Forum ist zum Wissensaustausch da. Es gab paar
Erklärungsansätze, diese wurden leider nicht zu Ende geführt. Ich bin ja
(zum Glück) nicht der Einzigste der versucht das eigentliche Problem zu
verstehen was gelöst werden soll.
Das eigentliche Thema dreht sich um einzelne, angeblich problematische,
Inkrements und Verbundoperatoren im Zusammenhang mit der 'volatile'
Kennzeichnung. Nicht mehr und nicht weniger. Hier fiel mir die Warnung
auf. Ich sehe da auch keine Mehrddeutigkeit von volatile. Das müßte auch
mal jemand erklären wo die sein soll.
Genauso hat noch niemand erklärt was alles notwendig ist um
volatile_load() und volatile_store()
zu nutzen. Welches Headerfile muss man einbinden? Wo ist das definiert?
Was gibts sonst noch zu beachten? Wilhelm, wie siehts aus? Muss die
Variable noch 'volatile' sein? Wird ein atomic Block noch benötigt?
Damit man überhaupt einmal über den Tellerrand schauen kann.
Jörg W. schrieb:> Weil es um Verbundoperatoren ging.Veit D. schrieb:> Mir ging es um die möglichen Unterschiede der> Inkrementimplentierung die im Thread mal aufgekocht sind.Jörg W. schrieb:> Wenn man keine Argumente weiter hat
Du darfst also etwas "pathologisch-unsinnig" nennen, aber wenn ich etwas
"Magic Number Schrott" nenne zählt das als "keine Argumente". Das ist
ein Super Argument™.
Du hast bis jetzt übrigens kein Argument gebracht außer "funktioniert
aktuell". Und das ist meiner Meinung nach nicht viel Wert ist.
mh schrieb:> zählt das als "keine Argumente"
Es ist deshalb kein Argument, weil es mit dem Thema absolut nichts zu
tun hat, ob da eine magic number steht oder ein symbolischer Name. Ich
habe mir die Mühe gemacht, dir den passenden rauszusuchen, interessiert
dich ja allerdings nicht.
Ja, ich fände es durchaus auch sinnvoller, wenn STM den Namen gleich
genommen hätte, aber am verwendeten Verbundoperator ändert es halt rein
gar nichts.
Dass ich überhaupt ein Stück Code direkt von STM genommen habe, sollte
dem Argument vorbeugen, dass ich nur unfähig wäre, vernünftigen Code
selbst zu produzieren. Selbstverständlich hat unser eigener Code noch
viel mehr davon (und dann auch ohne magic numbers), aber das wirst du ja
sowieso nicht wissen wollen.
Ja, ich finde ein Beispiel, bei dem auf der rechten Seite ein
volatile-Objekt mit Seiteneffekten zugegriffen wird, nach wie vor
pathologisch-unsinnig. Ich hätte nichts dagegen, wenn jemand den
Standard so formuliert, dass es dafür eine Warnung gibt und es von mir
aus auch als undefiniert erklärt wird, ob die Zuweisung nun das
volatile-Objekt nach der Operation erneut abfragen muss oder nicht (das
ist ja der wesentliche Unterschied in deinem Beispiel).
> Du hast bis jetzt übrigens kein Argument gebracht außer "funktioniert> aktuell".
Doch, viel weiter oben: es verursacht unsinnig viel Aufwand (den einem
auch kein Kunde bezahlen möchte, ein Compilerbauer erst recht nicht),
existierenden, funktionierenden Code von einer Form
1
a_volatile<op>=b;
komplett auf
1
a_volatile=a<op>b;
umzuschreiben. Außerdem konnte mir noch keiner erklären, warum die
zweite Form wohl definiert ist, die erste aber es (unter ansonsten
gleichen Umständen) nicht sein soll.
Hallo,
Jörg W. schrieb:> Außerdem konnte mir noch keiner erklären, warum die> zweite Form wohl definiert ist, die erste aber es (unter ansonsten> gleichen Umständen) nicht sein soll.
Seit bestehen des Threads, ab Eingangsposting, hab ich auch schon
mehrfach versucht nachzufragen und bis jetzt keine Antwort erhalten. Ich
vermute das es darauf einfach keine Antwort gibt. Woher auch. Die Frage
war von Anfang an aus meiner Sicht glasklar formuliert.
> "A compound assignment of the form E1 op= E2 is equivalent to the simple
2
> assignment expression E1 = E1 op (E2), except that the lvalue E1 is
3
> evaluated only once, and with respect to an indeterminately-sequenced
4
> function call, the operation of a compound assignment is a
5
> single evaluation."
6
>
>> Wenn E2 mit E1 irgendwas op machen muss, dann muss doch E1 erstmal> gelesen werden. Ansonsten kann keine op ausgeführt werden. Mir konnte im> gesamten Thread noch niemand das Problem darlegen was dabei schief gehen> soll, weil jeder nur antwortet "kann schief gehen". Von dem was schief> gehen kann redet bis jetzt niemand. Das ist das eigentliche Problem in> der gesamten Diskussion. Da helfen auch keine Zitate die nichts anderes> aussagen.
Da steht "except that the lvalue E1 is evaluated only once".
Bei Integraltypen macht das m.M. auch keinen Unterschied. Bei solchem
Code wohl schon:
Jörg W. schrieb:> mh schrieb:>> zählt das als "keine Argumente">> Es ist deshalb kein Argument, weil es mit dem Thema absolut nichts zu> tun hat, ob da eine magic number steht oder ein symbolischer Name.
Ich muss also hin nehmen, dass du etwas als "pathologisch-unsinnig"
bezeichnest und darf nicht darauf antworten, weil es nichts mit dem
Thema zu tun hat?
Jörg W. schrieb:> Ich habe mir die Mühe gemacht, dir den passenden rauszusuchen, interessiert> dich ja allerdings nicht.
Das ist eine Unterstellung.
Jörg W. schrieb:> Selbstverständlich hat unser eigener Code noch> viel mehr davon (und dann auch ohne magic numbers), aber das wirst du ja> sowieso nicht wissen wollen.
Und noch eine Unterstellung.
Jörg W. schrieb:> Ja, ich finde ein Beispiel, bei dem auf der rechten Seite ein> volatile-Objekt mit Seiteneffekten zugegriffen wird, nach wie vor> pathologisch-unsinnig.
Was ist daran unsinniger als
1
b=b+1;
2
a=b;
Sollte das nicht das gleiche sein? Und jeder lesende Zugriff auf
volatile Objekte kann Seiteneffekte haben. Warum ist "mein Zugriff" also
"pathologisch unsinnig"?
Jörg W. schrieb:> Ich hätte nichts dagegen, wenn jemand den> Standard so formuliert, dass es dafür eine Warnung gibt und es von mir> aus auch als undefiniert erklärt wird, ob die Zuweisung nun das> volatile-Objekt nach der Operation erneut abfragen muss oder nicht (das> ist ja der wesentliche Unterschied in deinem Beispiel).
Du willst daraus ernsthaft undefined behaviour machen? Dann kann man
volatile Objekten keinen Wert mehr zuweisen.
>> Du hast bis jetzt übrigens kein Argument gebracht außer "funktioniert>> aktuell".>> Doch, viel weiter oben: es verursacht unsinnig viel Aufwand (den einem> auch kein Kunde bezahlen möchte, ein Compilerbauer erst recht nicht),> existierenden, funktionierenden Code von einer Form> a_volatile <op>= b;> komplett auf> a_volatile = a <op> b;> umzuschreiben. Außerdem konnte mir noch keiner erklären, warum die> zweite Form wohl definiert ist, die erste aber es (unter ansonsten> gleichen Umständen) nicht sein soll.
Es ist beides nicht wohl definiert. Das Problem, das ich mit den
compounds habe, ist
> a_volatile <op>= b;
ist nicht das gleiche wie
> a_volatile = a <op> b;
Die einzige Lösung die ich sehe, ist eine Variante zu verbieten.
(Abgesehen von der Möglichkeit volatile in der aktuellen Form ganz zu
streichen und durch volatile_store und _load build-ins zu ersetzen, was
ich bevorzugen würde.)
Jörg W. schrieb:> Allerdings ist da das read-modify-write nicht mehr und nicht minder> „verschleiert“ als beim compound-Operator.
Genau dieses "verschleierte" RMW scheint wohl auch der einzige Grund für
die Deprication zu sein:
1
Volatile external modifications are only truly meaningful for loads and stores. Other read-modify-write operations imply touching the volatile object more than once per byte because that’s fundamentally how hardware works. These RMW operations are therefore misleading and should be spelled out as separate read ; modify ; write, ...
Ich habe mir jetzt diesen Abschnitt, in dem Herr Bastien die Deprecation
von Compound-Assignments an eine volatile Variable begründet
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1152r0.html#compound
zum gefühlt hundertsten Mal durchgelesen und glaube, ihn nun endlich
verstanden zu haben. Dass ich dafür so viele Anläufe brauchte, hat im
Wesentlichen zwei Ursachen:
1. Der Schreibstil des Autors ist für mein Dafürhalten nicht sehr
präzise. Deswegen rätselte ich bei manchen Formulieren lange, was er
wohl damit meinen könnte.
2. Ich suchte in dem Text verzweifelt nach einem Riesenproblematik, die
aber wohl nur in seinem, nicht aber in meinem Kopf existiert.
Das entscheidende Wort, das die ganze (vermeintliche) Problematik
beschreibt, ist
"misleading" (= irreführend)
Hier ist nun meine eigene Interpretation des Texts:
Der Einfachheit halber erläutere ich sie zunächst anhand einer einfachen
Variable:
1
volatileintv;
Auf Objekte im Speicher kann lesend oder schreibend zugriffen werden.
Ein Lesezugriff auf v wird bspw. mit folgendem Ausdruck durchgeführt:
1
x=v
Da v volatile ist, findet der Speicherzugriff auch tatsächlich statt und
wird vom Compiler nicht wegoptimiert.
Ein Beispiel für einen Schreibzugriff sieht so aus:
1
v=1
In der Anweisung
1
v=v+1
erfolgt erst ein Lese- und dann ein Schreibzugriff auf v.
In jedem der drei Beispiele taucht der Variablenname v im Ausdruck so
oft auf, wie Zugriffe auf sie stattfinden. Schreibt man den letzten
Ausdruck um in die äquivalente Form
1
v+=1
ist dies nicht mehr der Fall. Auch hier wird zweimal auf v zugegriffen
(erst lesend, dann schreibend), aber syntaktisch ist nur ein einzelnes v
zu sehen.
Genau das ist es wohl, was Herr Bastien für irreführend (misleading)
hält. Ein des Programmierens Unkundiger könnte beim Anblick dieses
Ausdrucks denken, da geschieht genau ein einziges Mal etwas mit v. Wenn
er dann mit dem Logic-Analyzer den Adress- und Datenbus des Computers
untersucht, erkennt er zu seiner großen Überraschung, dass da zwei
Zugriffe stattfinden.
Um diese Verwirrung zu vermeiden, möchte Herr Bastien die verkürzte
Schreibweise einfach abschaffen. Seine Aussage
1
These RMW operations are therefore misleading and should be spelled out
2
as separate read ; modify ; write
deutet darauf hin, dass ihm sogar die Schreibweise v=v+1 noch weh tut
und er dies lieber als
1
x=v;
2
x=x+1;
3
v=x;
sehen würde, so dass pro Anweisung maximal ein volatile-Zugriff erfolgt.
Aber warum das Ganze nur bei volatilen Variablen?
Nur bei volatilen Variablen ist die Anzahl und die Art der ausgeführten
Speicherzugriffe essentiell und für den Programmierer von Interesse. Bei
gewöhnlichen Variablen hingegen sind konkrete Speicherzugriffe ohne jede
Bedeutung, für den Programmierer ist ausschließlich das Ergebnis eines
Ausdrucks von Interesse.
Das Geschriebene gilt natürlich sinngemäß auch dann, wenn anstelle von v
ein dereferenzierter Pointer auf ein volatiles Objekt verwendet wird,
was ja einer der typischen Anwendungsfälle von volatile ist, so wie in
diesem Beispiel:
Fazit:
Wenn ich das richtig sehe, wird mit der Abschaffung von volatile
Compound-Assignments kein wirkliches Problem angegangen, sondern
lediglich mehr Klarheit in der syntaktischen Ausdrucksweise geschaffen.
Dies zählt für mich persönlich aber in die Kategorie Programmierstil und
hat in einer Sprachspezifikation nichts zu suchen.
Möglicherweise liege ich mit meiner Interpretation des verlinkten Textes
völlig falsch. In diesem Fall bitte ich darum, mich zu korrigieren und
dabei kurz darzulegen, wie der Text wirklich gemeint ist. Auch dann
hätte ich mein Ziel erreicht, nämlich endlich zu verstehen, wozu diese
dubiose Deprecation gut sein soll.
PS: Ich sehe gerade, dass Frank den Text ebenfalls gelesen hat und zur
gleichen Interpretation gekommen ist:
Frank _. schrieb:> Genau dieses "verschleierte" RMW scheint wohl auch der einzige Grund für> die Deprication zu sein:
Yalu X. schrieb:> PS: Ich sehe gerade, dass Frank den Text ebenfalls gelesen hat und zur> gleichen Interpretation gekommen ist:
Du warst nur etwas ausführlicher :)
Das einzige Problem was ich im Zusammenhang von volatile und compounds
sehe, sind dereferenzierte volatile Pointer.
Beitrag "Re: avr-gcc-10 - "volatile deprecated [-Wvolatile]" Warnungen"
Wobei ich mir nicht sicher bin, ob die Deprication hier überhaupt
greift.
Btw. Unabhängig von volatile aber ähnlich, wie sieht es eigentlich
hiermit aus:
Hallo,
Danke Yalu für deine Mühe. Jetzt habe ich das Problem verstanden. Also
ist das eher ein persönliches Ding von JF Bastien. Wäre umso
bedauerlicher.
Wegen Franks Code Bsp. mit dem Zeiger. Ich weiß nicht ob mich Frank aufs
Glatteis führen wollte oder nicht. Ich nehme an die Absicht war den Wert
von x zu inkrementieren. Dazu muss aber erst der Zeiger dereferenziert
werden um dann was sinnvolles damit zu machen, sonst zeigt der ins
Nirwana.
In der Praxis kann man das dann über Makros machen und ist dann auch
gleich gewappnet dafür, daß die Langschreibweise ebenfalls deprecated
wird. Etwa so:
1
#typedef uint32_t REG_TYPE
2
3
#define REG_AND(reg, val) do {REG_TYPE t = (reg); t &= (val); (reg) = t;} while 0
4
#define REG_OR(reg, val) do {REG_TYPE t = (reg); t |= (val); (reg) = t;} while 0
5
#define REG_XOR(reg, val) do {REG_TYPE t = (reg); t ^= (val); (reg) = t;} while 0
Nop schrieb:> n der Praxis kann man das dann über Makros machen
Wenn bei Argumenten keine Nebeneffekten auftauchen.
Taucht da irgendein x++ und wird die Variable mehrmals ersetzt, schon
gibt es das nächste Problem.
Veit D. schrieb:> Also> ist das eher ein persönliches Ding von JF Bastien. Wäre umso> bedauerlicher.
Hast du dir mal angeguckt, wer dieser JF Bastien ist? Falls nein,
solltest du das mal nachholen. Nur so als Info, er sitzt als "Apple C++
Lead" im Std-Committee. Das Paper hat es nahezu unbeschadet durch SG1
and EWG in San Diego Kona geschafft und ist erfolgreich im C++20
Standard gelandet. Das ist also ganz sicher ein "persönliches Ding" ;-).
Veit D. schrieb:> Wegen Franks Code Bsp. mit dem Zeiger. Ich weiß nicht ob mich Frank aufs> Glatteis führen wollte oder nicht. Ich nehme an die Absicht war den Wert> von x zu inkrementieren. Dazu muss aber erst der Zeiger dereferenziert> werden um dann was sinnvolles damit zu machen, sonst zeigt der ins> Nirwana.> int x = 0;> int volatile *ptr = &x;>> (*ptr)++;> *ptr += 1;> *ptr = *ptr + 1; // deutlicher wäre vielleicht *ptr = (*ptr) + 1;>> Ob der Zeiger volatile ist oder nicht spielt für das Ergebnis keine> Rolle. Mit volatile werden nur wieder beide Kurschreibweisen> angemeckert.
Du hast das volatile an die falsche Stelle gepackt. Es ist natürlich
wichtig, ob der Zeiger volatile ist. Nach dem Ausdruck
1
*p++;
ist der Wert von p unbekannt. Er kann ins Nirwana zeigen, muss es aber
nicht.
Nop schrieb:> In der Praxis kann man das dann über Makros machen
Das hatten wir beim AVR-GCC lange Zeit, und waren froh, dass man den
Mist endlich los war und standardmäßige C-Bit-Operationen benutzen
konnte.
Lange Zeit konnte der Compiler dort eben aus foo |= (1<<bar) kein SBI
foo, bar ableiten.
mh schrieb:> Nur so als Info, er sitzt als "Apple C++ Lead" im Std-Committee.
Das macht es nicht besser.
Ich unterstelle dem Standardkommittee nach wie vor in dieser Beziehung
komplette Abgehobenheit von den Leuten, die das dann in der Praxis
tatsächlich auch benutzen. Wann hat wohl das letzte Mal jemand von den
Damen und Herren einen Gerätetreiber geschrieben oder einen
Interrupt-Service? (Wohlgemerkt: wir reden hier über
lowlevel-Hardware-Zugriffe auf Bit-Ebene. Aber das ist halt einer der
primären Gründe, wofür man volatile 1989 überhaupt eingeführt hatte.)
Dass foo |= bar Bits setzt und foo &= ~bar Bits löscht, lernt man in
diesem Umfeld ziemlich schnell. Dass das letztlich ein read-modify-write
ist, ist implizit jedem völlig klar – spätestens, wenn man wirklich mal
drüber nachdenkt. *) Es gibt aus meiner Sicht nach wie vor keinen
nachvollziehbaren Grund, warum man für volatile-Objekte nun dieses
implizite read-modify-write abschaffen sollte, wenn letztlich denen, die
es benutzen, die Folgen davon bewusst sind. An allen anderen Stellen
(einfach mal den Sourcecode eines beliebigen Unix-Kernels ansehen) wird
es ja auch als Schreibweise für Bitmanipulationen im Sinne von r-m-w
benutzt.
*) Witzigerweise haben wir ja im Laufe der Diskussion bemerkt, dass es
für SBI / CBI bei AVR teilweise tatsächlich gar kein r-m-w ist, aber das
wiederum ist dann komplett unabhängig davon, ob man es mit
Verbundoperator oder ohne formuliert. :)
zitter_ned_aso schrieb:> Taucht da irgendein x++ und wird die Variable mehrmals ersetzt, schon> gibt es das nächste Problem.
Es geht doch gerade darum, eben das nicht zu machen.
Ihr stellt euch doch alle an wie Höhlenmenschen. Es ist doch völlig
klar, warum man die in-place-Operatoren bei Volatile abschaffen möchte.
Es ist eben nicht klar definiert, ob die Operation in-place durchgeführt
werden soll, oder per load+mod+store.
Jörg W. schrieb:> Wann hat wohl das letzte Mal jemand von den> Damen und Herren einen Gerätetreiber geschrieben oder einen> Interrupt-Service?
Im Linux-Kernel sind alle HW-Zugriffe schon immer über
accessor-functions.
Und es ist sehr sinnvoll.
Volatile-Variablen gibt es dort praktisch nicht.
Alles wird per accessor oder volatile_store/load-ähnliche Konstrukte
gemacht.
Sind das alles Idioten?
MaWin schrieb:> Im Linux-Kernel sind alle HW-Zugriffe schon immer über> accessor-functions.
Das hat allerdings andere Gründe.
Damit kann man Zugriffe vom zugrunde liegenden Bussystem abstrahieren.
Du könntest also bspw. ein Peripheral über SPI oder I²C ansteuern und
trotzdem den gleichen Treiber darüber benutzen.
mh schrieb:> Hast du dir mal angeguckt, wer dieser JF Bastien ist? Falls nein,> solltest du das mal nachholen. Nur so als Info, er sitzt als "Apple C++> Lead" im Std-Committee. Das Paper hat es nahezu unbeschadet durch SG1> and EWG in San Diego Kona geschafft und ist erfolgreich im C++20> Standard gelandet. Das ist also ganz sicher ein "persönliches Ding" ;-).
Habe schon mitbekommen das der bei Apple ist. Nur was hat das damit zu
tun wo er arbeitet? Jeder kann dumme Ideen haben, egal was er ist und wo
er arbeitet. Ich nehm irgendwas nicht als gegeben hin, nur weil es von
einem "hohen Tier" kommt. Wenn es Unsinn ist muss es hinterfragt werden.
Wir sind hier nicht in Japan oder China. Außerdem hatte hier im Thread
schon jemand geschrieben das das Komitee darüber noch diskutiert. Wer
weiß wie das durchgeboxt wurde.
Und wenn er die Kurzschreibweisen abschaffen möchte, warum dann nur auf
volatile Variablen bezogen. Oder war das nur der Anfang?
> Du hast das volatile an die falsche Stelle gepackt. Es ist natürlich> wichtig, ob der Zeiger volatile ist. Nach dem Ausdruck>
1
>*p++;
2
>
> ist der Wert von p unbekannt. Er kann ins Nirwana zeigen, muss es aber> nicht.
a) das Bsp. ist nicht von mir
b) habs nur dahingehend ausgebessert das es das macht was angedacht war
c) probiers selbst aus, egal wo volatile steht ob mit oder ohne, dass
Ergebnis ist immer gleich - mit meinem Code
Jörg W. schrieb:> Ich unterstelle dem Standardkommittee nach wie vor in dieser Beziehung> komplette Abgehobenheit von den Leuten, die das dann in der Praxis> tatsächlich auch benutzen. Wann hat wohl das letzte Mal jemand von den> Damen und Herren einen Gerätetreiber geschrieben oder einen> Interrupt-Service? (Wohlgemerkt: wir reden hier über> lowlevel-Hardware-Zugriffe auf Bit-Ebene.
Hast du auch mal versucht darauf eine Antwort zu finden? Ich unterstelle
dir jetzt einfachmal, dass du es nicht gemacht hast. Wenn ich mir
angucke, wer da drin sitzt, tauchen da genug mögliche Embedded Jobs im
Lebenslauf auf. Mal davon abgesehen entwickelt Apple eigene CPUs kümmert
sich um den ganzen lowlever Kram im eigenen OS. Das gleiche bei Intel,
eingene CPUs, GPUs, Modems, ... und mindestens den Linux lowlevel Kram.
Google baut eigene Chips und Treiber. NVIDIA ... GPUs und Treiber.
Glaubst du keins von diesen Unternehmen hat Vor- und Nachteile
abgewogen? Bist du dir sicher, dass du mehr Ahnung hast als alle
Vetreter dieser Unternehmen?
MaWin schrieb:> Jörg W. schrieb:>> Damit kann man Zugriffe vom zugrunde liegenden Bussystem abstrahieren.>> Nö.> Auch stinknormale MMIO-Zugriffe laufen über accessor.
Der wahre Grund für accessors ist natürlich, dass man damit nur eine
einzige Stelle hat, an der man sich um das dirty Business kümmern muss,
wie denn der Compiler jetzt ein bestimmtes Konstrukt umsetzt. Und man
kann dann sogar inline-assembly verwenden, wenn man ganz sicher gehen
will. Und falls sich der Compiler ändert, braucht man nur eine Stelle
anzupassen. Dass volatile so gut wie gar nicht definiert ist, ist schon
immer bekannt. Genau deshalb sollte man sich nicht auf das Verhalten
verlassen und die Verwendung zu gering wie möglich halten. Das bietet
diese Abstraktion.
Mit normalen Operationen auf volatile sprenkelst du diese Annahmen kreuz
und quer durch den kompletten Code. Das ist schlecht.
mh schrieb:> Veit D. schrieb:>> Also>> ist das eher ein persönliches Ding von JF Bastien. Wäre umso>> bedauerlicher.>> Hast du dir mal angeguckt, wer dieser JF Bastien ist? Falls nein,> solltest du das mal nachholen. Nur so als Info, er sitzt als "Apple C++> Lead" im Std-Committee. Das Paper hat es nahezu unbeschadet durch SG1> and EWG in San Diego Kona geschafft und ist erfolgreich im C++20> Standard gelandet.
Die ISO-Kollegen haben sich sicher genauso wie wir gefragt, was um alles
in der Welt JF mit seinem Vorschlag bezwecken möchte. Aber nachdem sie
sich vor Augen geführt haben, dass er ja DER große "Apple C++ Lead" ist,
hat keiner mehr gewagt, ihm zu widersprechen.
Tatsächlich ging es JF nur darum, C++ von – seiner Meinung nach –
unschönen Konstrukten zu befreien, der Sprache also sozusagen runde
Ecken zu verpassen ;-)
SCNR
Veit D. schrieb:> Ich nehm irgendwas nicht als gegeben hin, nur weil es von> einem "hohen Tier" kommt.
Manchmal sollte man einem Experten vertraunen. Vor allem wenn man selbst
keine Ahnung hast (Du hast selbst bewiesen, dass du nie wirklich den
Standard gelesen hast).
Veit D. schrieb:> Außerdem hatte hier im Thread> schon jemand geschrieben das das Komitee darüber noch diskutiert. Wer> weiß wie das durchgeboxt wurde.
Das kann man nachlesen wenn man möchte. Die Sitzungen sind übrigens
öffentlich, du kannst hingehen und deine Meinung vor Ort vertreten,
falls du dich traust.
Veit D. schrieb:> a) das Bsp. ist nicht von mir> b) habs nur dahingehend ausgebessert das es das macht was angedacht war
Ah du kannst also hellsehen. Dir ist klar, dass die Position des
volatile relativ zum * wichtig ist?
> c) probiers selbst aus, egal wo volatile steht ob mit oder ohne, dass> Ergebnis ist immer gleich - mit meinem Code
Das belegt nichts, außer für diesen Codeschnipsel mit deiner exakten
Compilerversion und den gleichen Einstellungen.
mh schrieb:> Glaubst du keins von diesen Unternehmen hat Vor- und Nachteile> abgewogen?
Große Unternehmen haben damit erstmal weniger ein Problem, die haben
ohnehin genügend Overhead, der Arbeitszeit verschlingt, da kommt es auf
ein paar Absolventen, die existierenden Code umschreiben müssen, nicht
vorrangig an. Das nimmt man da locker in Kauf.
Trotzdem sind die Zeiten, da diese Leute sowas wirklich selbst gemacht
haben, wohl in der Vergangenheit.
> Bist du dir sicher, dass du mehr Ahnung hast als alle> Vetreter dieser Unternehmen?
Nein, aber ich bin unmittelbar davon betroffen, wenn sich das wirklich
durchsetzt in der jetzt propagierten Form – und einen ernsthaften Nutzen
(außer: "das wird dann offensichtlicher") kann mir bisher immer noch
keiner demonstrieren.
Wenn schon, wäre es sinnvoller, das ganze Konzept "volatile" durch
irgendwas besseres, feiner granulares zu ersetzen (und dann vielleicht
auch Dinge wie die genannte Cache-Kohärenz etc. mit zu erfassen) – aber
da sehe ich nichts. Dann könnte man memory barriers, code reordering und
andere Schwachpunkte gleich mal mit anfassen, über die man auf der
unteren Ebene halt immer mal wieder stolpert.
Nur an einer Stelle am "volatile" herumzudoktorn weil angeblich etwas zu
wenig offensichtlich ist, ist nicht sinnvoll.
ps: Versteh mich nicht falsch. Ich bin der letzte, der sich weigert,
wegen Warnungen Code auch mal umzuschreiben – aber das muss auch
sinnvoll sein. All die in letzter Zeit hinzu gekommenen Warnungen über
Vermischung von vorzeichenhaften/vorzeichenlosen Ganzzahlen und
dergleichen habe ich durchaus dankbar aufgenommen, denn hin und wieder
zeigen sie einem, dass man über bestimmte Codestellen zuvor nicht gut
genug nachgedacht hat. Aber wenn ich stur foo |= bar durch foo = foo |
bar ersetzen soll, nur weil das angeblich offensichtlicher sei, dann
fehlt mir das Verständnis.
Mit der gleichen Begründung könnte man die Verbundoperatoren dann
schlicht komplett abschaffen – und Prä- und Postfixinkrement/-dekrement
gleich noch mit. Die sind doch in C nur erfunden worden, weil man durch
*p++ und *--p die Adressierungsarten der PDP-11 direkt abbilden konnte.
mh schrieb:> Das Paper hat es nahezu unbeschadet durch SG1> and EWG in San Diego Kona geschafft und ist erfolgreich im C++20> Standard gelandet. Das ist also ganz sicher ein "persönliches Ding"
So ganz geheuer ist denen das dann aber doch nicht. Siehe
Beitrag "Re: avr-gcc-10 - "volatile deprecated [-Wvolatile]" Warnungen"
Oliver
Oliver S. schrieb:> So ganz geheuer ist denen das dann aber doch nicht. Siehe
Schau'mer mal.
Wie geschrieben, es wäre ja absolut nichts einzuwenden, wenn man
volatile durch etwas besser durchdachtes, auf heutige Architekturen
passenderes ersetzen würde. Dann sollte aber zuerst ein brauchbarer
Ersatz da sein, und das sollte nicht nur 'ne umständlichere Syntax ohne
grundsätzlich anderes Konzept sein.
mh schrieb:> Wenn ich mir angucke, wer da drin sitzt, tauchen da genug mögliche> Embedded Jobs im Lebenslauf auf.
In den Bereichen, wo wirklich maschinennah (also mit direktem Zugriff
auf I/O-Register, Interrupts und dergleichen) programmiert wird, also
bspw. in Betriebssystemkernen und Mikrocontrollersteuerungen, dominiert
als Sprache nach wie vor C und nicht C++. Im C-Konsortium aber scheint
die Deprecation von volatile kein Thema zu sein, zumindest kann ich im
C2X-Draft nichts dazu finden.
Deswegen steckt in Jörgs Aussage IMHO durchaus ein Fünkchen Wahrheit:
Jörg W. schrieb:> Ich unterstelle dem Standardkommittee nach wie vor in dieser Beziehung> komplette Abgehobenheit von den Leuten, die das dann in der Praxis> tatsächlich auch benutzen.
Jörg W. schrieb:> Große Unternehmen haben damit erstmal weniger ein Problem, die haben> ohnehin genügend Overhead, der Arbeitszeit verschlingt, da kommt es auf> ein paar Absolventen, die existierenden Code umschreiben müssen, nicht> vorrangig an. Das nimmt man da locker in Kauf.
Du weißt also auch noch, wie das alles bei Intel, Goole, Apple und co
intern abläuft.
Yalu X. schrieb:> Deswegen steckt in Jörgs Aussage IMHO durchaus ein Fünkchen Wahrheit:>> Jörg W. schrieb:>> Ich unterstelle dem Standardkommittee nach wie vor in dieser Beziehung>> komplette Abgehobenheit von den Leuten, die das dann in der Praxis>> tatsächlich auch benutzen.
Nein, das bleibt weiterhin eine Unterstellung, solange ihr die Erfahrung
der Committee Mitglider in diesem Bereich nicht kennt.
Veit D. schrieb:> Wegen Franks Code Bsp. mit dem Zeiger. Ich weiß nicht ob mich Frank aufs> Glatteis führen wollte oder nicht. Ich nehme an die Absicht war den Wert> von x zu inkrementieren. Dazu muss aber erst der Zeiger dereferenziert> werden um dann was sinnvolles damit zu machen, sonst zeigt der ins> Nirwana.> int x = 0;> int volatile *ptr = &x;>> (*ptr)++;> *ptr += 1;> *ptr = *ptr + 1; // deutlicher wäre vielleicht *ptr = (*ptr) + 1;>> Ob der Zeiger volatile ist oder nicht spielt für das Ergebnis keine> Rolle. Mit volatile werden nur wieder beide Kurschreibweisen> angemeckert.
Bezieht sich das auf den Code:
Beitrag "Re: avr-gcc-10 - "volatile deprecated [-Wvolatile]" Warnungen"
?
Da ging es schon um voltile Pointer, also "int* volatile p". Wird da der
Wert von p (also die Adresse wo er hin zeigt) einmal oder zwei mal aus
dem Speicher gelesen?
Microsoft macht da übrigens folgendes draus:
1
(*p)++;
2
00ED105Dmoveax,dwordptr[p]
3
00ED1060incdwordptr[eax]
4
*p+=1;
5
00ED1062moveax,dwordptr[p]
6
00ED1065incdwordptr[eax]
7
*p=*p+1;
8
00ED1067moveax,dwordptr[p]
9
00ED106Amovecx,dwordptr[eax]
10
00ED106Cmoveax,dwordptr[p]
11
00ED106Fincecx
12
00ED1070movdwordptr[eax],ecx
In den ersten beiden Fällen wird der Pointer tatsächlich nur einmal
gelesen, im dritten Fall zweimal.
Und hier dürften die Kurzschreibweisen eigentlich auch nicht angemeckert
werden, da auf dem Pointer selbst ja gar kein RMW stattfindet.
Veit D. schrieb:> Frank _. schrieb:>>> wie sieht es eigentlich hiermit aus:>>> int* p;>> *p++ += 42;>>> Das ist ungültiger Syntax mit dem linken Operanden.>>> dürfte der Pointer hier nur einmal incrementiert werden?>> PS: Noch übler :)>>(*p++)++;> Hier macht schon das erste Inkrement Mist bzw. nicht das was man> beabsichtigt. Steht so auch nirgendswo in deinem Link.
Also der Microsoft Compiler frisst beides ohne murren und macht genau
das draus, was ich erwarten würde - den Wert, auf den der Pointer zeigt
ensprechent erhöhen und anschliessend jeweils einmal den Pointer selbst
incrementieren (mal vom uninitialisierten Pointer im geposteten Code
abgesehen).
Wenn ich den Standard richtig verstehe, dürfte das auch nicht mal UB
sein.
mh schrieb:> Du weißt also auch noch, wie das alles bei Intel, Goole, Apple und co> intern abläuft.
Ja. Ich war selbst 10 Jahre lang in einem Unternehmen vergleichbarer
Größe beschäftigt, und ich kenne auch Leute, die bei Intel waren.
Frank _. schrieb:> Also der xxxxx frisst beides ohne murren und macht genau> das draus, was ich erwarten würde
Es spielt für den Standard überhaupt keine Rolle, was irgendein Compiler
macht.
Jörg W. schrieb:> mh schrieb:>> Du weißt also auch noch, wie das alles bei Intel, Goole, Apple und co>> intern abläuft.>> Ja. Ich war selbst 10 Jahre lang in einem Unternehmen vergleichbarer> Größe beschäftigt, und ich kenne auch Leute, die bei Intel waren.
Damit bleibt es also bei einem Fall von Höhrensagen und der Rest ist es
mal wieder eine Unterstellung. Falls ihr es noch nicht gemerkt habt, ich
bin kein Fan von Unterstellungen.
MaWin schrieb:> Frank _. schrieb:>> Also der xxxxx frisst beides ohne murren und macht genau>> das draus, was ich erwarten würde>> Es spielt für den Standard überhaupt keine Rolle, was irgendein Compiler> macht.
Selbst der im Threadtitel genannte avr-gcc-10 frisst das problemlos und
ohne Warnungen. Also von "ungültiger Syntax" zu sprechen halte ich dann
schon für recht gewagt. Und "macht schon das erste Inkrement Mist bzw.
nicht das was man beabsichtigt" scheint ja zumindest für VC++ und gcc
auch nicht zu stimmen.
Ansonsten ist das aber sowieso eine andere Baustelle und hat mit dem
Ursprungspost nur insoweit zu tun, daß das nur einmalige Evaluieren bei
den Kurzschreibweisen als ein Grund für die Deprecation vermutet wurde.
Hallo,
@ mh:
eigentlich bist du es der im gesamten Thread Unterstellungen verbreitet.
Meine Verständnisprobleme habe ich komplett offen gelegt. Daraus
wolltest du mir den Vorwurf machen ich hätte das P1382R1 nicht gelesen.
@ Frank:
> Selbst der im Threadtitel genannte avr-gcc-10 frisst das problemlos und> ohne Warnungen. Also von "ungültiger Syntax" zu sprechen halte ich dann> schon für recht gewagt.
Irgendwas wurde da falsch zitiert. Dein ursprüngliches
Veit D. schrieb:> @ mh:> eigentlich bist du es der im gesamten Thread Unterstellungen verbreitet.> Meine Verständnisprobleme habe ich komplett offen gelegt. Daraus> wolltest du mir den Vorwurf machen ich hätte das P1382R1 nicht gelesen.
Das ist interessant. Wo genau habe ich das gemacht? Oder ist das eine
U....
Da wird m.M.n. der Versuch gemacht wird, die Leute vor sich selbst zu
beschützen, weil sie, nach der Meinung des Autors, oft nicht wissen was
sie tun. Oder, etwas moderater ausgedrückt, dass Compound-Ausdrücke die
Tatsache nicht offensichtlich machen, dass ein RMW vorliegt. Da die
Variable nur links auftaucht, könnte man meinen, dass nur ein
Schreibzugriff erfolgt.
Naja. Ich denke, man hat das recht schnell begriffen.
Ich denke, Apple hat so einen Tick, alles Idiotensicher zu machen. Das
ist eindrucksvoll, wenn man Anfänger ist, aber eher lästig, wenn man
erfahren ist. Und ausserdem wird ja immer wieder noch ein besserer Idiot
erfunden. :-)
Insgesamt eher ärgerlich, dass man sich mit so einem Sch... beschäftigen
muss.
mh schrieb:> Jörg W. schrieb:>> mh schrieb:>>> Du weißt also auch noch, wie das alles bei Intel, Goole, Apple und co>>> intern abläuft.>>>> Ja. Ich war selbst 10 Jahre lang in einem Unternehmen vergleichbarer>> Größe beschäftigt, und ich kenne auch Leute, die bei Intel waren.>> Damit bleibt es also bei einem Fall von Höhrensagen und der Rest ist es> mal wieder eine Unterstellung. Falls ihr es noch nicht gemerkt habt, ich> bin kein Fan von Unterstellungen.
Welcher Teil von "ich war selbst in <so einem Unternehmen> beschäftigt"
war denn "mehrdeutig"?
Theor schrieb:> Da wird m.M.n. der Versuch gemacht wird, die Leute vor sich selbst zu> beschützen
Das ist auch mein Gefühl / meine Befürchtung dabei.
Wohlgemerkt: das bezieht sich ausschließlich auf das „Verbot“ der
Verbundoperatoren, nicht auf „irgendwas mit volatile überhaupt“. Dass
das volatile-Konzept an manchen Stellen seine Ecken und Kanten und
Graubereiche hat, ist unstrittig. Damit werden wir aber wohl oder übel
leben müssen, solange sich niemand aufrafft, in dieser Hinsicht ein
besseres Konzept auf den Tisch zu legen. Die Unwägbarkeiten dabei in
Grenzen zu halten hilft es, möglichst wenig mit volatile zwischen zwei
Sequenzpunkten zu machen, also eben bspw. keine volatile-Operationen mit
zusätzlichen Seiteneffekten auf der rechten Seite zu verwenden.
Jörg W. schrieb:> Theor schrieb:>> Da wird m.M.n. der Versuch gemacht wird, die Leute vor sich selbst zu>> beschützen>> Das ist auch mein Gefühl / meine Befürchtung dabei.>> Wohlgemerkt: das bezieht sich ausschließlich auf das „Verbot“ der> Verbundoperatoren, nicht auf „irgendwas mit volatile überhaupt“.
Ja. Das sehe ich genauso. Es geht bei der "Patronage-Kritik" im Moment
nur um die Verbund-Operatoren.
He he. :-) Soweit ich weiß, darf jeder bei dem Komitee Papiere
einreichen. Vielleicht sollten wir das mal machen. So in der Art:
"We strongly reject the attempt to protect the programmers from
erroneous assumptions of which they are in no danger to act on, at all.
Even considered that beginners shall be taught about its very sense,
i.e. the operations of the machine, the subject is neither obscure nor
complex enough to justify such attempt."
> Dass> das volatile-Konzept an manchen Stellen seine Ecken und Kanten und> Graubereiche hat, ist unstrittig. [...]
Zweifellos. Na, ich muss mir den Rest auch mal durchlesen, wenn ich Zeit
habe. Furchtbares Englisch. Naja. Ob meins besser ist? :-)
Jörg W. schrieb:> Wohlgemerkt: das bezieht sich ausschließlich auf das „Verbot“ der> Verbundoperatoren, nicht auf „irgendwas mit volatile überhaupt“.
Ich denke, dass man die Falschpositiven der Warnung (es ist ja vorläufig
immer noch akzeptiertes C++) deutlich reduziert werden könnten, wenn man
in Fällen "<volatile var> <op>= <const, constexpr>" keine Warnung
generieren würde. Aber das müsste natürlich auch in den Standard :-)
Frank _. schrieb:> Also der Microsoft Compiler frisst beides ohne murren
Micrososoft hat für volatile defaultmässig sowieso eine eigene
Definition, die sollte man dan nicht als Beispiel nehmen.
Es macht auch prinzipiell überhaupt keinen Sinn, mit aktuellen Compilern
aktuell funktionieren Code zu testen. Das funktioniert, auch wenn es
nicht immer sauber definiert ist.
Die Probleme werden, wenn überhaupt, erst mit kommenden Compilern
auftreten, die, wie ja in der Vergangenheit schon öfter passiert,
aggressiver optimieren, und dadurch dann früher funktionierender Code
plötzlich nicht mehr funktioniert. Im Idealfall gibts dann
Compiletime-Fehler, aber vermutlich gibt das dann ganz übel zu findende
Laufzeitfehler.
Oliver
Frank _. schrieb:> Veit D. schrieb:>> Dein ursprüngliches*p++ += 42;>> frisst mein avr-gcc nicht.>> Komisch, meiner schon:
Hallo,
also, okay, so wie oben geschrieben, kompiliert es. Nur ist es wirklich
das was man mit einem Zeiger machen möchte? Der zeigt nämlich nach dem
Inkrement unkontrolliert sonst wohin. Deshalb hatte ich gestern den
Syntax dahingehend korrigiert das der Zeiger sinnvoll benutzt wird,
nämlich x inkrementieren/addieren.
Daraus ergäbe sich für diese spezielle Zeile theoretisch folgender
Syntax mit Klammersetzung zum Zeiger dereferenzieren und danach x
inkrementieren/addieren.
(*ptr)++ += 22;
Genau das kompiliert nicht. error: lvalue required as left operand of
assignment
Wie gesagt *ptr++ macht Unsinn, deswegen (*ptr)++.
Würde dann eher zu sowas tendieren o.ä.: *ptr = (*ptr) + 22 + 1
Frank, ich lasse dir gern meinen avr-gcc 10.1 (mingw64) zukommen, wenn
du möchtest.
Veit D. schrieb:> also, okay, so wie oben geschrieben, kompiliert es. Nur ist es wirklich> das was man mit einem Zeiger machen möchte? Der zeigt nämlich nach dem> Inkrement unkontrolliert sonst wohin.
Der zeigt vor dem Inkrement auf ein Element, und nach dem Inkrement auf
das nächste Element (von was auch immer). Das ist etwas, was man mit
Zeigern und Iteratoren üblicherweise so macht.
Oliver
Hallo,
alles klar, dann habe ich den Codeschnipsel falsch verstanden. Ich
dachte der sollte nur was mit x alleine machen und der Rest war zum
Fehler provozieren gedacht. Naja, egal, wie auch immer. Alles weitere
verkompliziert das nur noch. :-)
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1152r0.html> Importantly, volatile does not guarantee that memory operations won’t> tear, meaning that a volatile load may observe partial writes and> volatile stores may be observed in parts.
Das macht die Sache auch nicht einfacher.
Hallo,
https://embeddedartistry.com/blog/2019/03/11/improve-volatile-usage-with-volatile_load-and-volatile_store/
Hier wird das besagte Problem zwar verständlicher beschrieben. Nur was
mir noch nicht klar ist, fällt damit der bis jetzt meistens notwendige
atomic Block weg oder nicht? Wenn der wegfallen würde, also integriert
wäre, dann würde ich vielleicht :-) einen Sinn drin sehen. Also das es
einen Schutz vorm zerreißen bietet. Ansonsten bietet das keinen Schutz
vorm zerreißen sondern "nur" eine Lese/Schreib Garantie.
Ich dachte die sehen auch immer das Zereißproblem und wollen das mit
absichern. Mit Zerreißproblem denke ich bspw. an 2 Byte Variablen wo der
Zugriff durch irgendwas mittendrin unterbrochen wird und am Ende mit
einer zwischendrin geänderten 2 Byte Variablen falsch weiter handiert
wird.
Das müßten sie wenn dann konsequent mit angehen, denke ich.
Wenn nicht, bleibt ja die besagte Unsicherheit von der Verwendung
volatile und atomic weiterhin bestehen, wie im Dokument angeführt.
Veit D. schrieb:> Das müßten sie wenn dann konsequent mit angehen, denke ich.
Um Byte-Variablen wird sich das Standardkommittee vermutlich nicht
weiter scheren, das ist wirklich eine AVR-Nische. Im Zusammenhang mit
<signal.h> hat man sig_atomic_t definiert als einen Typen, für denen die
Atomizität garantiert ist, aber auf heute üblichen Architekturen sind
das natürlich alles (mindestens) 32 bit große Typen.
Aber ja, sowas wäre ein Punkt für eine verbesserte Ablösung von volatile
als Konzept.
Soweit ich das verstehe, ist die Situation eigentlich recht einfach
erklärbar:
1
volatileinta;
2
a=a&0x10;
3
4
volatileintb;
5
b&=0x10;
Im ersten Fall ist garantiert, dass ein Lese- und ein Schreibzugriff
stattfindet. Es gibt also exakt zwei Zugriffe auf das Objekt, die
möglicherweise Nebeneffekte auslösen.
Im zweiten Fall ist das nicht garantiert. Es gibt mindestens einen
Schreibzugriff auf das Objekt (weil es verändert wird), aber einen
Lesezugriff gibt es nur, wenn der Compiler eine RMW-Sequenz erzeugt.
Ob er eine RMW-Sequenz erzeugt, hängt von der Architektur und den
Optimierungseinstellungen ab. Daraus folgt, dass der Code mit "-O0"
gebaut möglicherweise zusätzliche Nebeneffekte auslöst, die der gleiche
Code mit "-Os" nicht auslöst. Für Hardwareregister ist so eine
Verhaltensänderung wirklich unangenehm.
Das Problem ist, dass es innerhalb des Sprachstandards von C++ keine
Möglichkeit gibt, das sauber zu definieren: Erzwingt man RMW (wie im
ersten Fall), dann darf ein avr-gcc kein SBI/CBI mehr generieren.
Verbietet man RMW, dann kann der Compiler wahrscheinlich keinen Code
generieren (gilt besonders, wenn es sich um ein Objekt handelt und nicht
nur einen Integer).
Daraus folgt für JF Bastien, dass man das problematische Konstrukt
abschaffen sollte. Diese Argumentation kann ich durchaus nachvollziehen.
Ob dieses Problem allerdings ein richtiges Problem ist, kann ich nicht
einschätzen.
Hardwareregister sind einerseits naturgemäß hardwarespezifisch,
andererseits kann ich die gleiche PCIe-Hardware an diverse Architekturen
koppeln - und bekomme dann möglicherweise unterschiedliches Verhalten,
wieder abhängig von der zugrundeliegenden Architektur. Es hängt also
schlicht davon ab, wie stark die eigenen Brillengläser getönt sind.
Jörg W. schrieb:> Um Byte-Variablen wird sich das Standardkommittee vermutlich nicht> weiter scheren, das ist wirklich eine AVR-Nische. Im Zusammenhang mit> <signal.h> hat man sig_atomic_t definiert als einen Typen, für denen die> Atomizität garantiert ist, aber auf heute üblichen Architekturen sind> das natürlich alles (mindestens) 32 bit große Typen.
Es gibt dann doch noch etwas mehr als sig_atomic_t in <stdatomic.h>.
S. R. schrieb:> Daraus folgt für JF Bastien, dass man das problematische Konstrukt> abschaffen sollte.
Wenn wir das Problem nicht lösen können, definieren wir es weg?
Klingt für mich eher nach Vogel Strauß als nach einer sinnvollen
Alternative.
Ich schrieb doch schon, von mir aus soll man sowas als
implementation-defined festlegen, oder implementation-dependant oder was
auch immer, aber nicht einfach nur den Deckel aufmachen, und das Problem
in der Tonne versenken wollen.
mh schrieb:> Es gibt dann doch noch etwas mehr als sig_atomic_t in <stdatomic.h>.
Ich habe auch absolut nichts über <stdatomic.h> geschrieben.
Jörg W. schrieb:> Ich schrieb doch schon, von mir aus soll man sowas als> implementation-defined festlegen, oder implementation-dependant> oder was auch immer, aber nicht einfach nur den Deckel aufmachen,> und das Problem in der Tonne versenken wollen.
C++ (und teilweise auch C) sind jetzt schon eine große Hölle von
"implementation-defined" und "undefined". Die Folgen sieht man auch hier
im Forum.
Dass C++ einfach so überkomplex ist, dass jeder nur ein Subset nutzt,
ist noch ein anderes Problem. Ich glaube, das C++-Gremium vereinfacht da
in die falsche Richtung - aber sie können auch nicht anders
vereinfachen, ohne Code kaputtzumachen.
Hallo,
die Lösung ist doch ganz einfach. Der Compiler muss nur die
Kurzschreibweise in die Langschreibweise übersetzen. Ich meine die
Kurzschreibweise ist doch laut meines Wissens nur für den tippfaulen
Menschen "eingebaut" wurden. Also wo ist das Problem das standardmäßig
vor der eigentlichen Übersetzung mit der Langschreibweise zu ersetzen?
Damit wären alle Problem gelöst. Keep simpel.
Und eigentlich hätte ich gedacht das wäre schon immer so gewesen. Würde
bedeuten die haben damals die Kurzschreibweise falsch eingebaut. Selbst
wenn nicht, werden jetzt Dinge extrem umständlich repariert.
Veit D. schrieb:> Der Compiler muss nur die Kurzschreibweise in die Langschreibweise> übersetzen.
Naja, so "einfach" ist das sicher nicht.
Wäre die Frage, was alles kaputt geht, wenn man die Verbundoperatoren so
definiert, dass sie das auf der linken Seite stehende Objekt einmal
lesend und einmal schreibend referenzieren müssen. Für nicht-volatile
Objekte sollte sich ja eigentlich nichts ändern dadurch.
Veit D. schrieb:> Also wo ist das Problem das standardmäßig vor der eigentlichen> Übersetzung mit der Langschreibweise zu ersetzen?
In deiner Annahme, dass sie das gleiche wären.
Sind sie nicht, vor allem in C++ nicht (getrennte Operatorüberladung).
Weil "+" ist eine Addition, "++" ist ein Increment.
Und ein Increment ist nunmal nicht dasselbe wie "Addition mit 1".
Das gilt auf unterer Ebene (siehe Assemblerhandbuch für i80 oder x86 -
unterschiedliche Codierungen, unterschiedliches Flag-Verhalten) genauso
wie auf der oberen Ebene (wenn ich z.B. Objekte habe, bei denen das
Einselement nicht "(int)1" ist).
mh schrieb:> Jörg W. schrieb:>> Um Byte-Variablen wird sich das Standardkommittee vermutlich nicht>> weiter scheren, das ist wirklich eine AVR-Nische. Im Zusammenhang mit>> <signal.h> hat man sig_atomic_t definiert als einen Typen, für denen die>> Atomizität garantiert ist, aber auf heute üblichen Architekturen sind>> das natürlich alles (mindestens) 32 bit große Typen.>> Es gibt dann doch noch etwas mehr als sig_atomic_t in <stdatomic.h>.Jörg W. schrieb:> mh schrieb:>> Es gibt dann doch noch etwas mehr als sig_atomic_t in <stdatomic.h>.>> Ich habe auch absolut nichts über <stdatomic.h> geschrieben.
Ja eben! Du hast nicht erwähnt, dass das "Zerreißproblem" seit c11
gelößt ist mit der Einführung von _Atomic und den Typedefs in
stdatomic.h.
Aber Hauptsache, man kann dem Standardkommittee wieder etwas
unterstellen.
S. R. schrieb:> Sind sie nicht, vor allem in C++ nicht (getrennte Operatorüberladung).
Da ist allerdings was dran (hatte ich ja auch viel weiter oben schon
erwähnt).
Insofern wäre es allerdings halt primär ein Grund für C++, nicht für C –
würde aber entsprechend gestaltete C-Header-Files der Hersteller für C++
unbrauchbar machen bzw. erfordern, dass alle Hersteller nun für ihre
Hardware irgendwelche C++-Abstraktionen parallel zu den "einfachen"
Bitoperationen für C anbieten.
Jörg W. schrieb:>> Du hast nicht erwähnt, dass das "Zerreißproblem" seit c11 gelößt>> Du auch nicht.
Außerdem hättest du natürlich Veit gegenüber dann auch noch erwähnen
sollen, dass das zwar durch das Standardkommittee gelöst worden ist,
aber ihm das für seinen AVR-GCC leider nichts hilft:
Jörg W. schrieb:> Nur vom Stanard allein implementiert es sich halt noch nicht im Compiler
Natürlich muss das jemand implementieren. Aber der Standard kann nichts
dafür, dass es niemand für den avr-gcc macht. Du hast die Schuld aber
zum Standardkommitte geschoben. Ich habe den Teil der Diskussion nochmal
zitiert auf den ich geantwortet habe.
Veit D. schrieb:> Ich dachte die sehen auch immer das Zereißproblem und wollen das mit> absichern. Mit Zerreißproblem denke ich bspw. an 2 Byte Variablen wo der> Zugriff durch irgendwas mittendrin unterbrochen wird und am Ende mit> einer zwischendrin geänderten 2 Byte Variablen falsch weiter handiert> wird.>> Das müßten sie wenn dann konsequent mit angehen, denke ich.>> Wenn nicht, bleibt ja die besagte Unsicherheit von der Verwendung> volatile und atomic weiterhin bestehen, wie im Dokument angeführt.Jörg W. schrieb:> Veit D. schrieb:>> Das müßten sie wenn dann konsequent mit angehen, denke ich.>> Um Byte-Variablen wird sich das Standardkommittee vermutlich nicht> weiter scheren, das ist wirklich eine AVR-Nische. Im Zusammenhang mit> <signal.h> hat man sig_atomic_t definiert als einen Typen, für denen die> Atomizität garantiert ist, aber auf heute üblichen Architekturen sind> das natürlich alles (mindestens) 32 bit große Typen.
Das Problem ist im Standard seit c11 gelöst mit _Atomic. Aber das
Problem interessiert in der AVR-Nische wohl niemanden so stark, _Atomic
auch für den avr-gcc umzusetzen.
Jetzt irgendwas an volatile ändern zu wollen, um tearing zu verhindern,
ist nicht wirklich hilfreich. Das Problem ist gelöst, auch für volatile,
und diese Änderung im Standard müsste ja auch erstmal jemand im avr-gcc
umsetzen.
Hallo Leute,
jetzt habt ihr mich soweit, dass ich nicht mehr mitkomme.
Auf meinem AVR kommen alle 4 Varianten zum gleichen Ergebnis.
a++;
++a;
a += 1;
a = a + 1;
Welche internen Flags das Rechenwerk zum rechnen selbst benötigt ist mir
ehrlich gesagt vollkommen egal. Allein die Rechnung muss stimmen.
Beim pre und post Inkrement kommt es darauf an wie man das verwendet. Ob
als Zwischenrechnung oder direkt verwendet. Der kleine Unterschied wann
man das Ergebnis wirklich hat. Darauf will ich aber gar nicht hinaus. Es
kommt darauf an, dass das Endergebnis, egal in welchen Rechenwerk, zum
gleichen Ergebnis führt. Wenn das woanders nicht so ist, dann verkrieche
ich mich wieder unter meinen AVR und freue mich das er das rechnet was
ich von ihm will. :-)
Moment mal, wenn ich hiermit rumspiele, sieht das AssemblerDump bei
allen Varianten untereinander gleich aus. Was mich daraus schließen
lässt, dass der gcc auf allen Rechenwerken die einfache Mathematik
beherrscht. :-) Demnach wandelt er wie vermutet alles korrekt um.
Ich habe da mal was vorbereitet ...
avr-gcc 9.2.0: https://godbolt.org/z/v5qCUE
x86-64 gcc 10.1: https://godbolt.org/z/xFAisg
RISC-V gcc 8.2.0: https://godbolt.org/z/qWmD6N
power64le gcc 6.3.0: https://godbolt.org/z/19DYpc
Wie lange das bei denen gespeichert bleibt weiß ich allerdings nicht.
Der Code besteht nur aus
mh schrieb:> Aber das Problem interessiert in der AVR-Nische wohl niemanden so stark,> _Atomic auch für den avr-gcc umzusetzen.
Möglicherweise auch deshalb nicht, weil es dort schon viel früher
dringlich genug war, sodass es mit <util/atomic.h> bereits seit 13
Jahren eine funktionierende Lösung gibt.
Für eine Umsetzung im Compiler wäre Johann der erste Kandidat, aber dem
hat man mittlerweile ja ziemlich komplett die Motivation genommen, am
AVR-GCC noch was zu machen.
MaWin (original) schrieb:> Veit D. schrieb:>> Ich habe da mal was vorbereitet ...>> Leider ohne volatile. Daher völlig am Thema vorbei.
Die Zeit für diese sinnlose Zeile hättest du nutzen sollen um 'volatile'
davor zu setzen und zu vergleichen.
Jörg W. schrieb:> Für eine Umsetzung im Compiler wäre Johann der erste Kandidat, aber dem> hat man mittlerweile ja ziemlich komplett die Motivation genommen, am> AVR-GCC noch was zu machen.
Wie jetzt? Hat Johann hingeschmissen?