Guten Morgen,
die "strict aliasing rule" besagt ja, dass zwei Zeiger, die einer
Funktion übergeben werden, vom Compiler als voneinander unabhängig
betrachtet werden können, was gewisse Optimierungen (Variablen in
Registern) erlaubt.
Eine Ausnahme ist ja die Standardfunktion memmove(), bei der sich die
über die Zeiger bechriebenen Speicherbereiche überschneiden dürfen.
Ich habe gerade einen ähnlichen Fall, bei der einer Funktion einen
Sende- und ein Empfangspuffer übergeben wird, wobei es durchaus nicht
verboten sein soll, dass diese identisch sind.
1
/** Daten per SPI senden unter Zuhilfenahme des DMA
2
*
3
* Die funktion nutzt den DMA, um die maximale Datenrate zu erreichen. Sie
4
* ist allerdings nicht optimal schnell, da sie erst zurueckkehrt, wenn
5
* alles ubertragen ist. Optimierungpotenzial ist also vorhanden, aber
6
* momentan unnoetig, da selbst bei einem TFT das Update ausreichend
7
* schnell ist.
8
*
9
* @param[out] receive: Daten von Slave
10
* @param[in] send: Daten an Slave
11
* @param[in] len: Pufferlaenge, maximal 65536
12
*
13
* Gilt receive == send, wird der Puffer ueberschrieben
14
* Gilt receive == NULL wird nur geschrieben, nichts gelesen
15
* Gilt send == NULL werden nur Nullen geschrieben */
/* Laesst Clock- und Daten-Pins floatend zurueck */
131
SPI_Cmd(SPIx,DISABLE);
132
}
Die strict aliasing rule hier wohl "nur" deshalb keine Rolle, weil das
Array per Hardware außerhalb des Betrachtungsbereichs des Compilers
gefüllt wird.
Was ich mich frage:
a) Ich habe in einigen Fällen den gleichen Speicherbereich als const
uint8_t* und uint8_t * übergeben. Kann das Ärger machen?
Die Unterscheidung ist deshalb drin, weil der Sendepuffer durchaus
auch aus Literalen im Flash bestehen kann. Dann ist der Empfangsbuffer
natürlich separat.
b) Bei den Implementierungen (=Quelltexten) von memmove(), die ich im
Netz gefunden habe, scheint strict aliasing keine besondere
Berücksichtigung zu finden. Warum?
Edit: Die Forensoftware weigert sich, die unnoetigen Leerzeilen löschen
zu lassen.
Walter T. schrieb:> die "strict aliasing rule" besagt ja, dass zwei Zeiger, die einer> Funktion übergeben werden, vom Compiler als voneinander unabhängig> betrachtet werden können
Nur wenn die Pointer unterschiedliche Typen haben! Was du meinst ist nur
der Fall wenn du das "restrict"-Keyword hinzunimmst. "char" (also auch
"uint8_t") Pointer dürfen als Ausnahme alles Aliasen, weshalb auch
memcpy, memmove & co funktionieren.
Walter T. schrieb:> a) Ich habe in einigen Fällen den gleichen Speicherbereich als const> uint8_t* und uint8_t * übergeben. Kann das Ärger machen?
Nö, das ist gleich doppelt erlaubt:
- Gleicher Typ => dürfen überlappen
- Vom Typ char => dürfen überlappen
Walter T. schrieb:> b) Bei den Implementierungen (=Quelltexten) von memmove(), die ich im> Netz gefunden habe, scheint strict aliasing keine besondere> Berücksichtigung zu finden. Warum?
Dito.
Mit anderen Worten: strict-Aliasing wird erst dann zum Problem, wenn man
"böse" Casts macht, z.B. "int*" nach "short*" o.ä., wobei eben als
Ausnahme der Cast auf Zeiger auf einen char-Typ erlaubt ist. Solche
"bösen" Casts sollte man sowieso nie machen (schlechter Stil), wodurch
sich das Problem in Luft auflöst. Interessanter wird's wenn man das
"restrict"-Keyword hinzu nimmt.
Programmierer schrieb:> Mit anderen Worten: strict-Aliasing wird erst dann zum Problem, wenn man> "böse" Casts macht, z.B. "int*" nach "short*" o.ä., wobei eben als> Ausnahme der Cast auf Zeiger auf einen char-Typ erlaubt ist.
Auch wenn mir diese Regel bekannt ist, frage ich mich doch, was der
technische Grund dafür ist. An welcher Stelle im Assembler-Code entsteht
das Problem?
Programmierer schrieb:> Nur wenn die Pointer unterschiedliche Typen haben!
Danke für den Hinweis! "strict aliasing" wird nicht unbedingt dadurch
einfacher, dass es in den Spielregeln (C-Standard) nicht behandelt wird.
Michael schrieb:> An welcher Stelle im Assembler-Code entsteht> das Problem?
Ist die Frage ernst oder ein Seitenhieb auf die Hochsprachen-Fraktion?
Wenn ersteres: John Regehr hatte mal etwas Schönes dazu in seinem Blog
geschrieben: https://blog.regehr.org/archives/1307
Es erlaubt Optimierungen, die sonst nicht möglich sind.
Hier ein kleines Beispiel:
https://godbolt.org/z/zj11xvo3r
Ohne Optimierungen gibt der Code 0x0123abab aus, mit Optimierungen
0x01234567. Bei anderen Compilern/Plattformen kann das Ergebnis
unterschiedlich sein.
Der Grund ist: Bei eingeschaltetem Optimizer liest der Compiler den Wert
"*foo" nur ein mal, vor dem ersten printf, aus dem Speicher (Wert
0x01234567), und behält ihn in einem Prozessor-Register. Weil der
Zugriff auf das "bar" auf einen anderen Typ stattfindet ("unsigned
short"), darf der Compiler annehmen, dass dieser den Wert des ersten
Zugriffs ("unsigned int") nicht beeinflusst, weshalb er den Wert nicht
erneut ausliest, und beim 2. printf erneut den einmalig gelesenen Wert
ausgibt. Bei abgeschaltetem Strict Aliasing oder eben bei allgemein
abgeschalteter Compiler-Optimierung wird diese Optimierung deaktiviert,
und nach jedem Pointer-Schreiben müssen alle anderen Pointer neu
ausgelesen werden (ineffizient).
Walter T. schrieb:> dass es in den Spielregeln (C-Standard) nicht behandelt wird.
Doch, es ist dort explizit und detailliert behandelt, mit allen
Ausnahmen. Es heißt da nur nicht "strict aliasing". Wenn du
Standard-Konformen Code schreibst, wird er funktionieren. Das Hadern mit
Strict Aliasing bzw. das Abschalten mit -fno-strict-aliasing wird nur
relevant, wenn man fehlerhaften Code schreiben möchte, wie z.B. im
Linux-Kernel, der nur bei abgeschaltetem Strict Aliasing funktioniert.
Walter T. schrieb:> dass es in den Spielregeln (C-Standard) nicht behandelt wird.
Im aktuellen Draft:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
unter Kapitel 6.5 "Expressions", Absatz 6-7, S. 77, sind die Regeln
definiert, wie auf Pointer/Union-Elemente zuzugreifen ist. Wenn du dich
daran hältst, funktioniert alles. Probleme entstehen erst, wenn man
meint davon abweichen zu müssen.
Programmierer schrieb:> Im aktuellen Draft unter Kapitel 6.5 "Expressions", Absatz 6-7, S. 77,
Danke! Ich habe schon gesucht, aber war noch nicht über die "Operators"
hinausgekommen. Vielleicht sollte ich diese 647 Seiten wirklich mal
lesen, aber die Realität geht ja doch mehr Richtung Strg-F.
Walter T. schrieb:> Vielleicht sollte ich diese 647 Seiten wirklich mal> lesen,
Naja, das macht keiner so wirklich außer Compiler-Autoren. Gute Bücher
sind wesentlich hilfreicher zum Lernen der Sprache. Wenn man eine
definitive Antwort auf ein spezielles Problem braucht kann man ja immer
noch Strg+F machen...
Walter T. schrieb:> Wenn ersteres: John Regehr hatte mal etwas Schönes dazu in seinem Blog> geschrieben: https://blog.regehr.org/archives/1307> Es erlaubt Optimierungen, die sonst nicht möglich sind.
Natürlich ernst.
Das ist schon ein sehr konstruiertes akademisches Beispiel. Der
bemängelt beispielsweise OpenSSL, dessen Funktion in unzähligen
Implementierungen gegeben ist.
Programmierer schrieb:> Das Hadern mit Strict Aliasing bzw. das Abschalten mit> -fno-strict-aliasing wird nur relevant, wenn man fehlerhaften Code> schreiben möchte, wie z.B. im Linux-Kernel, der nur bei abgeschaltetem> Strict Aliasing funktioniert.
Wieso sollte der Code fehlerhaft sein? Wenn das Ergebnis stimmt, ist der
Code nicht falsch. Er entspricht allenfalls nicht dem Standard.
Ihr versucht hier mit Gewalt Probleme zu konstruieren, die es in der
Praxis nicht gibt. Der Code des Threaderstellers wird ebenfalls keine
Probleme in dieser Hinsicht haben.
Michael schrieb:> Wieso sollte der Code fehlerhaft sein? Wenn das Ergebnis stimmt, ist der> Code nicht falsch. Er entspricht allenfalls nicht dem Standard.
Nun ja, da könnte man anderer Meinung sein.
Egal, hier gibt es was zum Nachlesen zum Thema:
https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8
Oliver
Walter T. schrieb:> Vielleicht sollte ich diese 647 Seiten...
Hoppla! Jetzt sind es 701 Seite. Also noch einmal 54 Seiten mehr als
das, was Jörg vor ein paar Wochen als Draft verlinkt hat. Der Text wird
schneller länger als ich lesen kann!
Michael schrieb:> Das ist schon ein sehr konstruiertes akademisches Beispiel.
Das sind wohl alle sehr kurzen, prägnanten Beispiele, die in zwei Zeilen
etwas auf den Punkt bringen sollen.
Michael schrieb:> Ihr versucht hier mit Gewalt Probleme zu konstruieren, die es in der> Praxis nicht gibt.
Ich mache ein "Code Review". In Anführungszeichen, weil das bei selbst
geschriebenem Code eigentlich nicht geht. Da ist es Sinn und Zweck der
Sache, überargwöhnisch zu sein.
Michael schrieb:> Wieso sollte der Code fehlerhaft sein? Wenn das Ergebnis stimmt, ist der> Code nicht falsch.
Nein! Das ist eine völlig falsche und gefährliche Sichtweise.
Insbesondere in C und C++ gibt es sehr viel Code, dessen Ergebnis zwar
korrekt aussieht, der aber dennoch fehlerhaft ist. Beim Portieren auf
eine andere Plattform, einen anderen Compiler, Ändern der
Compiler-Optionen usw. kann dieser Code plötzlich falsche Ergebnisse
liefern.
>Er entspricht allenfalls nicht dem Standard.
Code, der nicht dem Standard entspricht, ist falsch, da es keinerlei
Garantie gibt, dass er unter allen Bedingungen (Plattformen,
Compiler-Versionen/Optionen) das richtige Ergebnis liefert. Das kann
gerade im Embedded-Bereich schlimme Folgen haben (IIRC ist deswegen eine
Ariane-Rakete abgestürzt). Die meisten Compiler liefern zusätzliche
Garantien was funktioniert, aber dann hat man immer noch Probleme beim
Portieren auf andere Compiler.
Michael schrieb:> Ihr versucht hier mit Gewalt Probleme zu konstruieren, die es in der> Praxis nicht gibt.
z.B. der Linux-Kernel ist voll mit solchen Problemen. Wäre er das nicht,
könnte man ohne -fno-strict-aliasing kompilieren, was die Performance
verbessern würde.
Michael schrieb:> Das ist schon ein sehr konstruiertes akademisches Beispiel.
Solche "akademischen Beispiel" sind sehr verbreitet in existierendem
Code, insbesondere wenn es um Serialisierung und Netzwerkprotokolle
geht. Hier im Forum wird alle 3 Tage danach gefragt, und es kommen
sofort 100 Antworten welche die Strict-Aliasing-Rules verletzen, und
somit genau wie in meinem Beispiel nur bei abgeschalteter Optimierung
funktionieren. Rein zufällig gibt es auch alle 5 Tage eine Frage "Warum
funktioniert mein Code nur ohne Optimierungen?". Manche Firmen
kompilieren nie mit Optimierungen und kaufen lieber leistungsfähigere
Controller, weil sie es nicht schaffen korrekten Code zu schreiben.
Walter T. schrieb:> Hoppla! Jetzt sind es 701 Seite. Also noch einmal 54 Seiten mehr als> das, was Jörg vor ein paar Wochen als Draft verlinkt hat. Der Text wird> schneller länger als ich lesen kann!
Ich habe mich verguckt. Der Draft vom Dezember 2020 ist 54 Seiten kürzer
als der oben verlinkte Draft vom April 2011. Es geht also in die
richtige Richtung. :-)
[Edit]
Beitrag "Re: [gcc,clang] kein Error bei Funktionsaufruf mit falschen Parametern"
Programmierer schrieb:> Manche Firmen kompilieren nie mit Optimierungen und kaufen lieber> leistungsfähigere Controller, weil sie es nicht schaffen korrekten Code> zu schreiben.
Dein ganzer Beitrag zeugt von einer gänzlich gegensätzlichen Sichtweise
zwischen uns beiden.
Was nutzt ein Standard, der an der Praxis vorbeigeht? Was nutzt ein
Compiler, der diesen Standard einhält, aber sich nicht so verhält, wie
es die Anwender erwarten?
Gerade wenn es um Optimierungen usw. geht, sollte der vorhandene Code,
wie Linux usw., als Grundlage herhalten und sicherstellen, dass dieser
damit funktioniert.
Kann der Compiler nicht zweifelsfrei feststellen, dass die
Speicherbereiche nicht doch identisch sind, darf er nicht so optimieren,
dass dadurch Fehler bei der Ausführung entstehen können. Das sollte
eigentlich selbstverständlich sein. Es vom Datentyp des Parameters
abhängig zu machen ist verrückt. Klar, bei float und int mag es
konstruiert erscheinen, aber ein int* und ein void* als Parameter
derselben Funktion können durchaus identisch sein.
Ich kenne die Arbeit in Normgremien selbst, da kommt selten etwas
brauchbares heraus, Kompromisse dienen fast immer nur dazu, damit keiner
der Beteiligten einen Gesichtsverlust erleidet...
Michael schrieb:> Gerade wenn es um Optimierungen usw. geht, sollte der vorhandene Code,> wie Linux usw., als Grundlage herhalten und sicherstellen, dass dieser> damit funktioniert.
STOP!
Diese Diskussion ("Hat sich der GCC an den Linix-Kernel oder an den
C-Standard anzupassen?") hat sehr viele heiße Diskussionen in den
entsprechenden Feeds verursacht. Hier passt sie nicht hin. Hier geht es
nur um "strict aliasing" im Kontext "ARM-GCC". Um den IST-Zustand,
keinen SOLL-Zustand.
Michael schrieb:> Was nutzt ein Standard, der an der Praxis vorbeigeht?
Wo/Wieso tut er das?
Michael schrieb:> Was nutzt ein> Compiler, der diesen Standard einhält, aber sich nicht so verhält, wie> es die Anwender erwarten?
Wo ist klar definiert, was die Anwender erwarten? Im Standard.
Michael schrieb:> Gerade wenn es um Optimierungen usw. geht, sollte der vorhandene Code,> wie Linux usw., als Grundlage herhalten und sicherstellen, dass dieser> damit funktioniert.
So klappt das aber nicht. Wer definiert, welcher Code genau korrekt ist
und welcher nicht? Findest du, Strict Aliasing sollte aus dem Standard
entfernt werden, sodass der Linux-Code korrekt wird, aber dafür der
gesamte C-Code langsamer?
Michael schrieb:> Kann der Compiler nicht zweifelsfrei feststellen, dass die> Speicherbereiche nicht doch identisch sind
Das kann er praktisch nie.
Michael schrieb:> Das sollte> eigentlich selbstverständlich sein.
Bei FORTRAN ist es genau eben nicht so, da gibt es kein Aliasing,
weshalb FORTRAN bis heute einen Geschwindigkeitsvorteil hat. Um das in C
nachzubilden gibt es Strict Aliasing und das "restrict" Keyword.
Michael schrieb:> aber ein int* und ein void* als Parameter> derselben Funktion können durchaus identisch sein.
void* kann man eh nicht dereferenzieren, also kein Problem.
Michael schrieb:> Es vom Datentyp des Parameters> abhängig zu machen ist verrückt.
Es ist naheliegend, dass Pointer unterschiedlichen Typs nicht auf das
gleiche zeigen können.
Hast du jetzt ein Problem mit Strict Aliasing im Speziellen oder dem
C-Standard im Allgemeinen? Wenn du nur Strict Aliasing nicht magst und
mit dem Geschwindigkeitsnachteil leben kannst (ich höre c-hater schon
lachen), kannst du gerne mit -fno-strict-aliasing kompilieren.
Wenn du findest, dass der ganze Standard so umgebaut werden sollte dass
er viel nachlässiger ist und auch kein Undefined Behaviour kennt (was ja
bis jetzt ebenfalls der Performance zugute kommt), kannst du auch
einfach Java verwenden, denn da ist es genau so: Code, der das korrekte
Ergebnis liefert, tut das wahrscheinlich immer und ist korrekt. Wenn
Multithreading ins Spiel kommt, stimmt das natürlich auch nicht mehr.
Walter T. schrieb:> Hier passt sie nicht hin. Hier geht es> nur um "strict aliasing" im Kontext "ARM-GCC". Um den IST-Zustand,> keinen SOLL-Zustand.
Das Ganze ist sowieso weder ARM- noch GCC-spezifisch. Das o.g. Beispiel
ist amd64, und das ist bei anderen Compilern ganz genauso.
Programmierer schrieb:> void* kann man eh nicht dereferenzieren, also kein Problem.
Haha. Zum Dereferenzieren brauche ich einen Cast und dann fängt das
Spiel doch an...
Programmierer schrieb:> Es ist naheliegend, dass Pointer unterschiedlichen Typs nicht auf das> gleiche zeigen können.
Sehe ich nicht so. Für den Compiler sind zwei Structs unterschiedlich,
obwohl sie identisch aufgebaut sind. Und die genannte "Vererbung" (ein
Struct beginnt mit einem anderen Struct) ist für mich durchaus legitime
Verwendung.
Programmierer schrieb:> Wo ist klar definiert, was die Anwender erwarten? Im Standard.
Das ist absurd. Ich habe diesen Standard nicht geschrieben, das ist
nicht, was ich oder viele andere Anwender erwarten. Das ist das, was das
Normgremium beschlossen hat.
Die Frage ist, was für den Hersteller des Compilers relevant ist. Es gab
Firmen, die ihre Kunden zufrieden stellen wollten. Bei GCC hat das heute
sowieso eine merkwürdige Richtung eingeschlagen...
Michael schrieb:> Haha. Zum Dereferenzieren brauche ich einen Cast und dann fängt das> Spiel doch an...
Und auf was möchtest du den void* casten, und wieso kannst du das nicht
anders lösen?
Michael schrieb:> Für den Compiler sind zwei Structs unterschiedlich,> obwohl sie identisch aufgebaut sind.
Das stimmt nur halb, es gibt im Kontext von Unions die "common initial
sequence".
Michael schrieb:> Und die genannte "Vererbung" (ein> Struct beginnt mit einem anderen Struct) ist für mich durchaus legitime> Verwendung.
Das lässt sich aber auch lösen, indem man den "upcast" explizit macht,
d.h. den Pointer auf das "Basis-Element" übergibt.
Michael schrieb:> Das ist absurd. Ich habe diesen Standard nicht geschrieben, das ist> nicht, was ich oder viele andere Anwender erwarten.
Na dann schreibe deinen eigenen Standard und hoffe dass ihn jemand
implementiert. Oder benutze einfach eine Sprache in der das schon so
ist.
Michael schrieb:> Bei GCC hat das heute> sowieso eine merkwürdige Richtung eingeschlagen...
Wieso, die sind doch sogar so nett und bieten -fno-strict-aliasing an,
was erwartest du denn noch, dass das standardmäßig an ist?
Programmierer schrieb:> was erwartest du denn noch, dass das standardmäßig an ist?
Ja, zum Beispiel. "Invasive Optimierungen" sollten nur dann greifen,
wenn der Anwender weiß, was er tut.
Was ist in der Praxis häufiger vertreten? Genaue Kenntnis über diese
"Strict Aliasing"-Geschichte? Oder Code, der diese verletzt?
Es bleibt festzustellen, dass es mit älteren Compilern kaum solche
Fragestellungen gab. C89 funktionierte einwandfrei, heute kommen alle
paar Jahre neue Versionen der Standards. Das heutige C++ zum Beispiel
hat keinerlei Ähnlichkeit mehr zu dem, was ich damals kennenlernte in
den Neunzigern...
Michael schrieb:> Ja, zum Beispiel. "Invasive Optimierungen" sollten nur dann greifen,> wenn der Anwender weiß, was er tut.
Praktisch alle Optimierungen sind invasiv auf die eine oder andere Art,
und die sind auch nur an wenn man -O übergibt. Was jetzt standardmäßig
an oder aus ist ist Haarspalterei. Ich finde es gefährlich,
standardmäßig nicht-standard-konformen Code durchzuwinken.
Michael schrieb:> Was ist in der Praxis häufiger vertreten? Genaue Kenntnis über diese> "Strict Aliasing"-Geschichte? Oder Code, der diese verletzt?
C ist eine Systems Programming Sprache, um effizienten Low-Level-Code zu
implementieren. Es geht nicht darum, diese für Anfänger einfach zu
machen. C ist ein kompliziertes aber mächtiges Werkzeug, das man
bedienen können muss. Für alles andere gibt es andere Sprachen. C auf
Kosten der Performance zu vereinfachen wäre so wie ein Formel-1 Auto mit
Kofferraum und Klimaanlage auszustatten.
Michael schrieb:> Es bleibt festzustellen, dass es mit älteren Compilern kaum solche> Fragestellungen gab.
Dafür waren die auch langsamer.
Michael schrieb:> C89 funktionierte einwandfrei
C89 hatte Strict Aliasing auch schon, das war schon immer Teil der
Sprache! Nur weil die uralten Compiler - bzw. die, die du verwendet hast
- das nicht ausnutzen konnten...
Michael schrieb:> Es bleibt festzustellen, dass es mit älteren Compilern kaum solche> Fragestellungen gab. C89 funktionierte einwandfrei, heute kommen alle> paar Jahre neue Versionen der Standards.
K&R, Ansi/C90, C99, C11, C18, ...
Stimmt, das geht so irrsinnig schnell voran, da kann man wirklich kaum
Schritt halten. Da ist ja noch nicht mal die Tinte trocken, schon gibt
einen neuen Standard ;)
Michael schrieb:> Das heutige C++ zum Beispiel> hat keinerlei Ähnlichkeit mehr zu dem, was ich damals kennenlernte in> den Neunzigern...
Bisher war das alles immer abwärtskompatibel, und du kannst dem
Compilern sagen, welchen Standard du gerne hättest. Der C++-Standard
hindert dich nicht daran, C++-Code so zu schreiben, wie du es
(kennen-)gelernt hast.
Oliver
Programmierer schrieb:> Es geht nicht darum, diese für Anfänger einfach zu machen.
Ich bezweifle, dass der Linux-Kernel von Anfängern entwickelt wird.
Oliver S. schrieb:> Der C++-Standard hindert dich nicht daran, C++-Code so zu schreiben, wie> du es (kennen-)gelernt hast.
Das ist korrekt. Aber der Code, mit dem man heute konfrontiert wird,
nutzt das teilweise intensiv. Glücklicherweise ist in meinem Unternehmen
mittlerweile alles ausdrücklich verboten, was nach C++03 kam.
Das geht einfach in die falsche Richtung, aus meiner Sicht. Für Viele
war C++ im Prinzip "C mit Klassen", also als solches wie es auch
erfunden wurde. Manche wollen aber mit dem aktuellen C++ Java und C#
usw. noch überholen...
Michael schrieb:> Ich bezweifle, dass der Linux-Kernel von Anfängern entwickelt wird.
Eine Menge Treiber kommen von Firmen, die nicht immer die Kompetentesten
sind... Aber die Strict-Aliasing-Entscheidung kommt von Linus Torvalds,
und der hat sowieso spezielle Ansichten. Wahrscheinlich ist die Codebase
einfach zu groß um es umzustellen, schließlich kompiliert der
Linux-Kernel auch nur mit dem GCC mit ganz bestimmten Einstellungen.
Michael schrieb:> Glücklicherweise ist in meinem Unternehmen> mittlerweile alles ausdrücklich verboten, was nach C++03 kam.
Gibt es dafür einen technischen Grund, oder ist nur keine Zeit zum
Lernen da? Schließlich kann man mit dem neuen C++ effizienteren,
kompakteren, wartbareren Code schreiben.
Michael schrieb:> Manche wollen aber mit dem aktuellen C++ Java und C#> usw. noch überholen...
Klar, C++ hat schon immer Dinge ermöglicht die in anderen Sprachen nicht
gehen. So kann man z.B. mit dem "neuen" Speichermodell (C++11) sehr
effizient Multithreading nutzen, was in den anderen Sprachen zwar
einfacher, aber auch weniger effizient ist. C++03 unterstützt offiziell
überhaupt kein Multithreading, weshalb man auf nicht-portable
Plattform-Spezifische Lösungen zurückgreifen muss - IMO nicht sehr
erstrebenswert.
Programmierer schrieb:>> Klar, C++ hat schon immer Dinge ermöglicht die in anderen Sprachen nicht> gehen. So kann man z.B. mit dem "neuen" Speichermodell (C++11) sehr> effizient Multithreading nutzen, was in den anderen Sprachen zwar> einfacher, aber auch weniger effizient ist. C++03 unterstützt offiziell> überhaupt kein Multithreading, weshalb man auf nicht-portable> Plattform-Spezifische Lösungen zurückgreifen muss - IMO nicht sehr> erstrebenswert.
Ich benutze C++ auf einem Arm Prozessor Bare Metal. Bei 190K Flash und
32K Ram ist dann nicht viel möglich für die C++ Features ab 2011.
Da ist nun mal kein Betriebsystem mit Threads darunter und auch new
Operatoren kosten extrem. Nichts mit Maps und Vektoren, die permanent
reallozieren. Da ist dann sofort der Speicher verhunzt.
Ich bleibe schön bei 'altem C++' weil ich damit auf Embedded Prozessoren
arbeiten kann. Die neuen Features ignoriere ich, weil die nicht portabel
sind.
Programmierer schrieb:> Wahrscheinlich ist die Codebase einfach zu groß um es umzustellen, schließlich
kompiliert der
> Linux-Kernel auch nur mit dem GCC mit ganz bestimmten Einstellungen.
Das funktioniert als Ausrede für die Inkompatibilitäten mit dem
C-Standard im existierenden Code. Aber mit jeder Zeile die neu
hinzukommt oder geändert wird, könnte man sich an die Regeln halten.
Dann würde der Unterschied mit der Zeit immer kleiner, statt immer
größer.
PittyJ schrieb:> Ich benutze C++ auf einem Arm Prozessor Bare Metal. Bei 190K Flash und> 32K Ram ist dann nicht viel möglich für die C++ Features ab 2011.> Da ist nun mal kein Betriebsystem mit Threads darunter und auch new> Operatoren kosten extrem. Nichts mit Maps und Vektoren, die permanent> reallozieren. Da ist dann sofort der Speicher verhunzt.>> Ich bleibe schön bei 'altem C++' weil ich damit auf Embedded Prozessoren> arbeiten kann. Die neuen Features ignoriere ich, weil die nicht portabel> sind.
Und was ist mit all den Features, die keinen zusätlichen Ram oder Flash
benötigen, sondern evtl. zu einer Ersparnis führen?
PittyJ schrieb:> Ich benutze C++ auf einem Arm Prozessor Bare Metal. Bei 190K Flash und> 32K Ram ist dann nicht viel möglich für die C++ Features ab 2011.PittyJ schrieb:> Die neuen Features ignoriere ich, weil die nicht portabel> sind.
Variadische templates, constexpr, <cstdint> & co kosten nichts an
Speicher und eigenen sich super für Mikrocontroller. Die Atomics, welche
mit C++11 bzw. C11 eingeführt wurden, funktionieren auch für
Mainloop<->ISR Synchronisation ohne Betriebssystem und passen genau auf
die Atomic-Instruktionen von ARM's, die man sonst ohne Inline Assembly
nicht nutzen könnte.
Ich fürchte, ihr werdet die Diskussion zu keinem fruchtbaren Ergebnis
bringen. Beide Seiten haben gute Gründe. Und die Diskussionen in den
Mailinglisten und Feeds dazu sind ewig lang. Und immer noch nicht
fertig.
Für die Besitzstandswahrer ist der Quelltext das Tafelsilber, das nicht
durch neue Compilervarianten beeinträchtigt werden sollte.
Für die Verbesserer ist es wichtiger, neben den älteren neueren
Anforderungen gerecht zu werden.
Meine persönliche Meinung ist es ja, dass Quelltext ein Investitionsgut
ist, dass über 7 Jahre abgeschrieben gehört. Und genau wie man auch
Maschinen und Gerätschaften weit über die Abschreibungsperiode hinaus
betreiben kann, ist man auch hier dafür selbst verantwortlich, sie am
Laufen zu halten und ggf. zu warten oder warten zu lassen.
Bei vielen Maschinen ist es sogar so, dass Umbauten auch immer
automatisch die Pflicht beinhalten, auch aktuelle (Sicherheits-)
Standards einzuhalten. Aber so weit würde ich bei Quelltext nicht gehen
wollen.
Michael schrieb:> Glücklicherweise ist in meinem Unternehmen> mittlerweile alles ausdrücklich verboten, was nach C++03 kam.
Jeder ist seines Glückes Schmied...
Oliver
Programmierer schrieb:> PittyJ schrieb:>> Ich benutze C++ auf einem Arm Prozessor Bare Metal. Bei 190K Flash und>> 32K Ram ist dann nicht viel möglich für die C++ Features ab 2011.>> PittyJ schrieb:>> Die neuen Features ignoriere ich, weil die nicht portabel>> sind.>> Variadische templates, constexpr, <cstdint> & co kosten nichts an> Speicher und eigenen sich super für Mikrocontroller. Die Atomics, welche> mit C++11 bzw. C11 eingeführt wurden, funktionieren auch für> Mainloop<->ISR Synchronisation ohne Betriebssystem und passen genau auf> die Atomic-Instruktionen von ARM's, die man sonst ohne Inline Assembly> nicht nutzen könnte.
oder auch std::span, ist ein super Ding!
Gibt es auf github als freie Implementierung, das funktioniert dann auch
mit älteren Compilern bis der eigene Compiler C++20 kann.
C++ ist genauso schlank und effizient wie C - you only pay for what you
use.
Gibt aber immer noobs die objektoriente Programmierung in C++ mit
Interfaces und Vererbung mit einzelnen Funktionen in C vergleichen.
Auch in C programmiert man ojektorientiert und das kostet dann genauso
viel.
Programmierer schrieb:> Variadische templates, constexpr, <cstdint> & co kosten nichts an> Speicher und eigenen sich super für Mikrocontroller.
Oder schon so einfache Erleichterungen der Schreibarbeit wie range-based
for oder auto. Und auch lambdas können hilfreich sein. Damit ist ein
std::sort effizienter als ein qsort.
Programmierer schrieb:> [...] schließlich kompiliert der> Linux-Kernel auch nur mit dem GCC mit ganz bestimmten Einstellungen.
Totaler Quatsch, das geht auch mit LLVM. Und schon vor > 10 Jahren hat
das LinuxDNA-Projekt den Kernel mit Intels ICC kompiliert.
Nur_ein_Typ schrieb:> Und schon vor > 10 Jahren hat das LinuxDNA-Projekt den Kernel mit Intels> ICC kompiliert.
Allerdings hat Intel einen nicht ganz unerheblichen Aufwand in den
Compiler gesteckt, um das zu ermöglichen.
mh schrieb:> Aber mit jeder Zeile die neu> hinzukommt oder geändert wird, könnte man sich an die Regeln halten.> Dann würde der Unterschied mit der Zeit immer kleiner, statt immer> größer.
Aber warum sollte man sich an den schwachen Regelsatz des Standards
halten, wenn die meiste Hardware sowieso stärkere Zusicherungen erlaubt?
C ist ein recht "lockerer" Standard, der davon ausging,
dass Programmierer und Compilerbauer die selbe Person sind,
oder sich zumindest nicht das Haxl legen.
Das muss auch so sein, weil C alles vom 8 Bit Mikrocontroller mit 256
Bytes
Ram bis zum Cray Supercomputer abdeckt.
Die neue Generation der Compiler Entwickler sieht ihren Baum, aber nicht
mehr den Wald, kommt frisch von der Uni,
ist blitzgescheit, ehrgeizig und hat Langeweile.
Der C Standard bietet Schlupflöcher für Optimierungen, die in 1 von 1000
Fällen ein paar Prozent Geschwindigkeitsvorteil bringt.
Kein Informatiker mit 10 Jahren Industriepraxis würde auf die Idee
kommen, diese Schlupflöcher auszunutzen.
Dazu gehört die Strict Aliasing Geschichte.
Aber auch signed overflow.
Neuere gcc wissen nicht mehr, wie signed Arithmethik funktioniert.
(-fwrapv nicht vergessen).
In der Praxis spielen diese Optimierungen sogut wie nie eine Rolle,
hauen aber funktionierenden Code zusammen.
Das sieht man schön darin, dass Compiler wie der NT WinDDK 7.10
cl.exe konstant die kleinsten Files generieren, die auch oft noch
schneller sind, als etwa der 2019 cl oder der gcc.
Dazu sind die alte Compiler auch noch schneller beim Compilieren (*).
Dazu kommen Anwender, die konstant alles mit -O3 oder -O2 Übersetzen,
anstatt mit konservativerem -O1, wie es früher üblich war,
als man noch genau wissen wollte, wie C Statements übersetzt werden.
Leiden tut der Anwender und die Reputation der Sprache.
(*)
Walter T. schrieb:> Meine persönliche Meinung ist es ja, dass Quelltext ein Investitionsgut> ist, dass über 7 Jahre abgeschrieben gehört. Und genau wie man auch
Reichlich naiv...
aber wir leben ja in einer Wegwerfgesellschaft.
udok schrieb:> Die neue Generation der Compiler Entwickler sieht ihren Baum, aber nicht> mehr den Wald, kommt frisch von der Uni,> ist blitzgescheit, ehrgeizig und hat Langeweile.> Der C Standard bietet Schlupflöcher für Optimierungen, die in 1 von 1000> Fällen ein paar Prozent Geschwindigkeitsvorteil bringt.> Kein Informatiker mit 10 Jahren Industriepraxis würde auf die Idee> kommen, diese Schlupflöcher auszunutzen.
Ihr versteht alle den Sinn von C nicht. C ist für hocheffiziente
Systemprogrammierung und nicht umsonst als Super-Assembler bezeichnet. C
sollte immer mit Assembler vergleichbare Ergebnisse erzielen. Wer diese
Performance nicht braucht und nur "normale" Anwendungen schreibt
("Industriepraxis"), benutzt mit C einfach die falsche Sprache. Leider
hat sich die gesamte Embedded Industrie und auch Lehre auf C
eingeschossen und missbraucht es für "normale" Anwendungen anstatt eine
andere, freundlichere Sprache zu etablieren, wie es die Informatiker für
andere Bereiche schon längst haben (C#, Java, PHP, JS, Python, ....).
Anstatt also an Compiler-Entwicklern rumzunörgeln dass sie ihren Job
tun, solltet ihr einfach mal aufhören C für etwas zu missbrauchen für
das es nie gedacht war und euch für andere Sprachen öffnen.
udok schrieb:> anstatt mit konservativerem -O1, wie es früher üblich war,
C ohne Optimierung zu übersetzen ist wie mit dem Ferrari nur in Gang 1
zu fahren. Da hätte es auch ein VW getan, aber der ist wohl nicht cool
genug.
Wenn C euch zu kompliziert ist, benutzt doch einfach mal Matlab, das
wird doch sowieso ständig als Allheilmittel angepriesen. Das hat solche
Probleme nicht.
udok schrieb:> Der C Standard bietet Schlupflöcher für Optimierungen, die in 1 von 1000> Fällen ein paar Prozent Geschwindigkeitsvorteil bringt.
Ich würde es eher so sagen: Der C-Standard lässt dem Compiler viele
Freiheiten zur Optimierung, da sonst an einigen Stellen für ein paar
Spezialfälle zusätzlicher Code eingefügt werden müsste, der selten nötig
ist, aber meistens das Programm langsamer macht.
> Kein Informatiker mit 10 Jahren Industriepraxis würde auf die Idee> kommen, diese Schlupflöcher auszunutzen.
Was offiziell im Standard steht, sind keine "Schlupflöcher".
> Aber auch signed overflow.> Neuere gcc wissen nicht mehr, wie signed Arithmethik funktioniert.> (-fwrapv nicht vergessen).
Die wissen, dass ein signed overflow in C offiziell undefiniert ist und
verhalten sich entsprechen.
Bewusst am Standard vorbei zu programmieren und das dann mit
irgendwelchen Compiler-Optionen gerade zu biegen, ist viel eher, was ich
als Ausnutzung von Schlupflöchern bezeichnen würde.
> In der Praxis spielen diese Optimierungen sogut wie nie eine Rolle,> hauen aber funktionierenden Code zusammen.
Nein, sie hauen kaputten Code zusammen. Code, der auf Grund seiner
Fehler nur auf niedrigen Optimierungsstufen das tut, was er soll, ist
für mich kein "funktionierender Code", sondern Schrott.
Rolf M. schrieb:> Nein, sie hauen kaputten Code zusammen. Code, der auf Grund seiner> Fehler nur auf niedrigen Optimierungsstufen das tut, was er soll, ist> für mich kein "funktionierender Code", sondern Schrott.
Dann musst du halt die Codebasis der letzen 50 Jahre überarbeiten...
Da stelle ich mir eher die Frage:
Hat der Compilerbauer einfach Mist gemacht?
Gerade Signed Arithmethik (mit definiertem Überlaufverhalten)
ist seit dieser Zeit eigentlich bis auf Ausnahmen im DSP Bereich
Standard.
Dazu kommt ja auch noch: Der C-Standard sagt ja nicht, dass das
Überlaufverhalten nicht erlaubt ist, er sagt nur, dass es dem
Compilerbauer
überlassen ist, wie er damit umgeht.
Im stillen Einverständnis, dass der Compilerbauer für die
Zielarchitektur die beste Wahl trifft.
Und da krankt es am gcc ganz gewaltig.
udok schrieb:> Rolf M. schrieb:>> Nein, sie hauen kaputten Code zusammen. Code, der auf Grund seiner>> Fehler nur auf niedrigen Optimierungsstufen das tut, was er soll, ist>> für mich kein "funktionierender Code", sondern Schrott.>> Dann musst du halt die Codebasis der letzen 50 Jahre überarbeiten...
Dass es viel fehlerhaften Code gibt, bedeutet nicht, dass man die Fehler
einfach weiter machen sollte.
> Da stelle ich mir eher die Frage:> Hat der Compilerbauer einfach Mist gemacht?
Nein, hat er nicht. Den C-Standard gibt es schon lange. Der Compiler
hält sich in diesem Fall daran, der Code nicht. Ganz offensichtlich
liegt der Fehler beim Code, bei dessen Entwicklung falsche Annahmen
getroffen wurden.
> Gerade Signed Arithmethik (mit definiertem Überlaufverhalten)> ist seit dieser Zeit eigentlich bis auf Ausnahmen im DSP Bereich> Standard.
Das Ziel der Compilerbauer ist nicht, bewusst dafür zu sorgen, dass
"undefiniertes Verhalten" auch tatsächlich etwas undefiniertes macht.
Das ergibt sich eben indirekt aus Optimierungen.
> Dazu kommt ja auch noch: Der C-Standard sagt ja nicht, dass das> Überlaufverhalten nicht erlaubt ist, er sagt nur, dass es dem> Compilerbauer überlassen ist, wie er damit umgeht.
Nicht nur. Er sagt, vor allem auch, dass der Compiler damit gar nicht
umgehen muss. Er darf annehmen, dass das Programm so geschrieben ist,
dass ein signed-Überlauf niemals stattfindet. Er braucht diesen Fall
daher gar nicht erst zu berücksichtigen.
> Im stillen Einverständnis, dass der Compilerbauer für die> Zielarchitektur die beste Wahl trifft.
Nein. Das wäre unspecified oder implementation-defined behavior.
signed-overflow ist aber undefined behavior, das heißt, der
Compilerbauer muss gar nichts wählen.
udok schrieb:> Gerade Signed Arithmethik (mit definiertem Überlaufverhalten)> ist seit dieser Zeit eigentlich bis auf Ausnahmen im DSP Bereich> Standard.
Aber nicht C-Standard. Um das noch mal deutlich zu sagen: Korrekter
(d.h. standard-konformer) C-Code von 1990 kompiliert auch heute noch
absolut korrekt. Die Compiler-Bauer haben da nichts "verschlimmbessert",
es funktioniert alles immer noch genau so wie immer. Lediglich
fehlerhafter Code fällt jetzt wahrscheinlicher auf die Nase, dafür wird
korrekter Code schneller. Und da Geschwindigkeit sowieso so ziemlich der
einzige Grund ist, C und C++ zu verwenden, ist das sehr zu begrüßen.
Wenn Geschwindigkeit nicht höchste Priorität hat, ist C und C++ schlicht
die falsche Wahl.
Rolf M. schrieb:> Die wissen, dass ein signed overflow in C offiziell undefiniert ist und> verhalten sich entsprechen.
Der (nicht definierte) Überlauf von signed ist m.E. der häufigste Fall
von "toleriertem UB" und darum gefährlich. Im Embedded-Bereich würde es
bei Timern und (neu-alt) auf 2er-Komplement-Maschinen die Casts oder ifs
ersparen.
Man kann sich streiten, warum es eingeführt wurde. Wegen der vielen
HW-Implementierungen zu der Zeit, um Sonderlocken zu vermeiden? Oder um
Optimierungen zu ermöglichen weil es undefiniert ist? Beipiel:
1
int8_t debug;
2
int foo(int8_t i)
3
{
4
debug=100+i;
5
return i<30;
6
}
Die Funktion darf Dank debug immer 1 zurückgeben.
Hier eine konforme Version für + und - von
http://c-faq.com/misc/sd26.html> Here is a complete set of three functions for ``careful'' addition,> subtraction, and multiplication.> (Note: these functions are still not perfect, and may fail if invoked> on various edge cases, such as the smallest negative integer, INT_MIN.)
A. S. schrieb:> Man kann sich streiten, warum es eingeführt wurde. Wegen der vielen> HW-Implementierungen zu der Zeit, um Sonderlocken zu vermeiden? Oder um> Optimierungen zu ermöglichen weil es undefiniert ist? Beipiel:
Damals war 2-er Kompliment noch nicht so verbreitet, da gab es noch
1-er Kompliment, Vorzeichenbits, und Saturated Arithmetik.
Diese Optimierungen sind völlig sinnlos, weil damit nie ein
Geschwindigkeitsproblem gelöst wird,
der Code ist ja aus einem wichtigen Grund drinnen!
Aber funktionierender Code wird damit völlig unnötig zerstört.
udok schrieb:> Aber funktionierender Code wird damit völlig unnötig zerstört.
Die Zeit, in der Codequalität nach "tut doch" bewertet wurde, ist aber
auch schon lange vorbei.
Oliver
Spannende Diskussion! :-)
Noch mal ein Hinweis aus der Praxis: Neben den Compilern gibt es auch
immer mehr andere Tools, die den Code lesen. Statische Code Analyse
sollte genau die selben Annahmen machen, wie der Compiler. Sanitizer
prüfen zur Laufzeit ob der Code sich an den Standard hält.
Wenn man vom Standard abweicht, muss man damit leben, dass der Code
nicht portierbar ist, Optimierungen den Code brechen und das obige Tools
im Projekt nicht einsetzbar sind. Evtl. muss ich auch den Warning-Level
meines Compilers zurück drehen.
udok schrieb:> Damals war 2-er Kompliment noch nicht so verbreitet, da gab es noch> 1-er Kompliment, Vorzeichenbits, und Saturated Arithmetik.>> Diese Optimierungen sind völlig sinnlos, weil damit nie ein> Geschwindigkeitsproblem gelöst wird,> der Code ist ja aus einem wichtigen Grund drinnen!> Aber funktionierender Code wird damit völlig unnötig zerstört.
Das ist doch aber gerade der Punkt: Da wird nichts zerstört. Wenn du
weißt, dass deine Hardware 2er Komplement konsequent unterstützt, nimmst
du eben "-fwrapv". Ist dann natürlich nicht mehr auf
1er-Komplement-Maschinen portierbar.
Wenn man die Anmerkungen zum Speichermodell des Linux-Kernels liest,
sind da auch Zusicherungen, die der C-Standard nicht macht. Und da
kommen auch noch neue dazu, wenn alte Hardware nicht mehr unterstützt
wird. Und gerade diese Grundannahmen wären wirklich schwer im Code zu
erkennen, weil sie sich direkt in einzelnen Codezeilen widerspiegeln.
Yalu X. schrieb:> udok schrieb:>> return i+1 > i;>> Wer so etwas als Ersatz für> return i != INT_MAX;>> schreibt, fällt zurecht auf die Nase.>> Dasselbe gilt für> c = abs(c);> if (c < 0)> continue;>> Beides ist Code, der mit der alleinigen Absicht geschrieben wurde, dem> Leser ein "Häh?" zu entlocken.
Die meisten Compiler bieten eine builtin Funktion für
Addition+Overflow-Check an. In C++ kann man das sogar noch richtig
verwenden, weil man da trotzdem noch einfach "a+b" schreiben kann. Aber
im Ernst: In C? Wer schreibt denn statt "a+b" echt
"__builtin_add_overflow"?
Al Fine schrieb:> Wer schreibt denn statt "a+b" echt> "__builtin_add_overflow"?
Der Kreis schließt sich wieder. Ich. Manchmal braucht man das Wissen, ob
ein Überlauf stattgefunden hat. Und diese builtin-Funktion ist das beste
Mittel, unter C an das Carry-Bit zu gelangen.
Walter T. schrieb:> Al Fine schrieb:>> Wer schreibt denn statt "a+b" echt>> "__builtin_add_overflow"?>> Der Kreis schließt sich wieder. Ich. Manchmal braucht man das Wissen, ob> ein Überlauf stattgefunden hat.
Die "gefährlichen" Fälle sind nur leider die, wo das unerwartet kommt.
Al Fine schrieb:> Das ist doch aber gerade der Punkt: Da wird nichts zerstört. Wenn du> weißt, dass deine Hardware 2er Komplement konsequent unterstützt, nimmst> du eben "-fwrapv". Ist dann natürlich nicht mehr auf> 1er-Komplement-Maschinen portierbar.
Eben, die Logik gehört umgedreht! -fwrap muss der default sein, es gibt
seit 20 Jahren praktisch nichts anderes mehr.
Wer glaubt dass er die Optimierung braucht, der muss -fno-wrap anmachen.
Dazu kommt dass man Warnungen nicht mal mit -Wall immer bekommt.
Ein guter Compiler muss gutmütig sein, und Überraschungen minimieren.
Es bleibt eh noch immer genug an Unklarheiten in der libc übrig.
>> Wenn man die Anmerkungen zum Speichermodell des Linux-Kernels liest,> sind da auch Zusicherungen, die der C-Standard nicht macht. Und da> kommen auch noch neue dazu, wenn alte Hardware nicht mehr unterstützt> wird. Und gerade diese Grundannahmen wären wirklich schwer im Code zu> erkennen, weil sie sich direkt in einzelnen Codezeilen widerspiegeln.
Jeder Code mit mehr als 1000 Zeilen lebt nicht im luftleeren Raum.
Da stecken immer Annahmen dahinter, viele davon implizit.
Die grösste Stärke von C ist der Präprozessor.
Der ist ein wichtiger Grund für den Erfolg von C.
Praktisch jedes sinnvolle Program steckt voll mit #ifdef - #define -
#else - #endif Anweisungen.
Das ist nichts anderes als das Abfangen von Compiler-, Bibliotheks- und
hardwarespezifischen Sonderfällen.
C++ löst das Problem mit Templates und Konstantenausdrücken, die
wegoptimiert werden. Lesbarer wird es damit aber auch nicht.
Yalu X. schrieb:> udok schrieb:>> return i+1 > i;>> Wer so etwas als Ersatz für> return i != INT_MAX;
In dem konstruierten Fall hast du recht. Man könnte auch einfach
unsigned
verwenden (unsigned hat definiertes Overflow Verhalten).
Aber es gibt halt auch viele reale und sicherheitskritische
Überlauf Abfragen, die mit der sinnlosen Optimierung nicht mehr
funktionieren. Das ist einfach nur Verschwendung von Lebenszeit.
udok schrieb:> C++ löst das Problem mit Templates und Konstantenausdrücken, die> wegoptimiert werden. Lesbarer wird es damit aber auch nicht.
Das bezweifle ich. Sobald man keine einzige Verwendung von nackten
Datentypen mehr hat, sondern nur noch templates zB mit @build-time
definierbarer Overflow-Policy ergibt sich eine ganz neue Qualität. Das
mit Macros nachzubauen ist wohl eher eine Übung zum abgewöhnen.
Al Fine schrieb:> Das bezweifle ich. Sobald man keine einzige Verwendung von nackten> Datentypen mehr hat, sondern nur noch templates zB mit @build-time> definierbarer Overflow-Policy ergibt sich eine ganz neue Qualität. Das> mit Macros nachzubauen ist wohl eher eine Übung zum abgewöhnen.
Von der Warte aus betrachtet, ist es übrigens schön, dass es die Option
gibt, Overflows undefined sein zu lassen. Das sollte es auch für
unsigned geben!
udok schrieb:> Damals war 2-er Kompliment noch nicht so verbreitet, da gab es noch> 1-er Kompliment, Vorzeichenbits, und Saturated Arithmetik.
Letztere gibt es auch heute.
> Diese Optimierungen sind völlig sinnlos, weil damit nie ein> Geschwindigkeitsproblem gelöst wird,> der Code ist ja aus einem wichtigen Grund drinnen!
Du meinst, um einen Fall abzuchecken, der eigentlich gar nicht auftreten
dürfte.
> Aber funktionierender Code wird damit völlig unnötig zerstört.
Das wiederholst du hier immer wieder, aber es stimmt nicht. Der Code war
schon immer fehlerhaft. Der Fehler ist nur bisher nicht aufgefallen.
udok schrieb:> Eben, die Logik gehört umgedreht! -fwrap muss der default sein, es gibt> seit 20 Jahren praktisch nichts anderes mehr.
Offenbar schon, denn sonst würde das ja schon von sich aus auch ohne
funktionieren.
> Ein guter Compiler muss gutmütig sein, und Überraschungen minimieren.
Er muss sich gemäß Standard verhalten. Und er muss keine Sonderfälle
berücksichtigen, zu denen der Standard ausdrücklich sagt, dass er sie
nicht berücksichtigen muss.
> Jeder Code mit mehr als 1000 Zeilen lebt nicht im luftleeren Raum.> Da stecken immer Annahmen dahinter, viele davon implizit.
… und viele davon falsch. Gerade falsche Annahmen sind eine der größten
Fehlerquellen überhaupt in der Programmierung.
> Die grösste Stärke von C ist der Präprozessor.> Der ist ein wichtiger Grund für den Erfolg von C.
Und doch ist er gleichzeitig das, was in allen danach entwickelten
Sprachen auf Teufel-komm-raus vermieden wird.
Ich halte es für sinnvoll, Threads mit der Überschrift "ARM-GCC" von C++
freizuhalten.
Im Gegenzug halten wir auch Threads mit der Überschrift "ARM-G++" von C
frei.
Deal?
Walter T. schrieb:> Ich halte es für sinnvoll, Threads mit der Überschrift "ARM-GCC"> von C++> freizuhalten.>> Im Gegenzug halten wir auch Threads mit der Überschrift "ARM-G++" von C> frei.>> Deal?
Aber gcc schluckt "-std=c++2a"...
Al Fine schrieb:> Aber gcc schluckt "-std=c++2a"...
Touché. Aber es nervt trotzdem. Ich halte mich ja auch in C++-Threads
damit zurück, wie einfach doch alles in Matlab geht.
Walter T. schrieb:> Touché. Aber es nervt trotzdem. Ich halte mich ja auch in C++-Threads> damit zurück, wie einfach doch alles in Matlab geht.
Richtig. In C hat man für die Masse an Code die Optionen
- fwrapv verwenden
- vor jeder Rechnung brav prüfen, ob sie denn nicht überläuft
- katastrophale Fehler in Kauf nehmen
Die 2 ist auch aus Performance-technischer Sicht alles andere als
anzuraten.
Torsten R. schrieb:> Wenn man vom Standard abweicht, muss man damit leben, dass ... das obige Tools> im Projekt nicht einsetzbar sind.
Nein. Solche über Jahre üblichen UBs sind quasi immer dort
konfigurierbar. Wäre auch weltfremd, wenn die Prüfer ein eigenes
Universum an Interpretationen erzwingen. Gerade im embedded Bereich.
Walter T. schrieb:> Ich halte es für sinnvoll, Threads mit der Überschrift "ARM-GCC" von C++> freizuhalten.
GCC ist die GNU Compiler Collection, die unter anderem einen
C++-Compiler beinhaltet. Und gcc ist laut manpage der "GNU project C and
C++ compiler".
Al Fine schrieb:> In C hat man für die Masse an Code die Optionen> - fwrapv verwenden> - vor jeder Rechnung brav prüfen, ob sie denn nicht überläuft
Warum sollte ich z.B. bei einem
1
for(inti=0;i<100;++i)
vor dem Inkrement jedes mal prüfen, ob i vielleicht überlaufen könnte?
> - katastrophale Fehler in Kauf nehmen
Rolf M. schrieb:> GCC ist die GNU Compiler Collection, die unter anderem einen> C++-Compiler beinhaltet.
Und "strict alias" ist ein typisches C- und kein C++-Problem, wenn die
Jungs artig sind und auf Referenzen anstatt Zeigern arbeiten.
Rolf M. schrieb:> Warum sollte ich z.B. bei einem> for (int i = 0; i < 100; ++i)> vor dem Inkrement jedes mal prüfen, ob i vielleicht überlaufen könnte?
Hast du nicht in Gedanken den Beweis geführt, bevor du das Beispiel
gepostet hast? Warum denn gerade 100?
Walter T. schrieb:> Und "strict alias" ist ein typisches C- und kein C++-Problem, wenn die> Jungs artig sind und auf Referenzen anstatt Zeigern arbeiten.
oh, in C++ gibt es keine Zeiger mehr?
Da muß ich kein bad boy sein.
Oder ich bin nicht gut genug in C++, aber eine doppelt verkettete Liste
mit Referenzen statt Zeigern kriege ich nicht hin.