Hallo zusammen,
ich möchte einen P-Regler programmieren und bin gerade zu dumm dafür.
Hier mein Code:
1
int32_tP_Teil;
2
int32_te;// Regeldifferenz
3
uint8_tP;// Verstärkung
4
while(1){
5
e=T_soll-T_ist;
6
7
if((P*e)<65535&&(P*e)>-65535)
8
{
9
P_Teil=P*e;
10
}
11
elseif((P*e)>65535)P_Teil=65535;
12
elseif((P*e)<(-65535))P_Teil=(-65535);
13
}
Mein Problem ist, dass sobald der P_Teil bei einer negativen
Regeldifferenz zu 65535 wird anstatt negativ zu werden. Ich probiere
jetzt schon einige Zeit und übersehe meinen Fehler.
Vielen Dank für eure Hilfe, leider bin ich noch Anfänger in der
Programmierung.
Gruß
Palavel
Pavel schrieb:> Mein Problem ist, dass sobald der P_Teil bei einer negativen> Regeldifferenz zu 65535 wird anstatt negativ zu werden.
Der signed Überlauf ist in C und C++ unspezifiziert und mündet in ein
Undefined Behavior.
Dann gilt das ganze Programm als Fehler behaftet, ist als total kaputt
anzusehen.
Martin schrieb:> uint <-> int ?
Ich tue mich etwas schwer, die Regeldifferenz kann sowohl positiv als
auch negativ werden, deswegen int32_t. Bei dem P_Teil das gleiche. Die
Verstärkung hat einen festen, positiven Wert deswegen uint8_t.
Danke für eure Geduld.
Pavel
Eigentlich alles richtig.
Vermutlich ist dein int 16 bit, so dass die Zahlen mit U oder L
qualifiziert werden sollten.
Aber was genau ist Dein Fehler? Also wo tritt er auf?
Was willst Du denn regeln und wie schnell muß es sein?
Ich hab die Erfahrung gemacht, wenn nichts dagegen spricht, macht man
eine Regelung vorzugsweise in float. Besonders alle Arten von
Temperaturregelungen sind aus CPU-Sicht schnarch langsam.
Ich würde aber nicht absichtlich Rechenzeit vernichten, d.h. einen
Ausdruck nicht an 5 Stellen nochmal ausrechnen lassen. Einmal sollte
reichen. Das ist dann auch übersichtlicher.
Peter D. schrieb:> Ich würde aber nicht absichtlich Rechenzeit vernichten, d.h. einen> Ausdruck nicht an 5 Stellen nochmal ausrechnen lassen. Einmal sollte> reichen. Das ist dann auch übersichtlicher.
Das sollte der Optimizer regeln.
Hallo,
was sind denn die zu erwartenden Maximalwerte (min/max) für P und e?
Dann kennt man die zu erwartenden Maximalwerte der Rechenergebnisse und
kann weiterschauen ...
Pavel schrieb:> e = T_soll - T_ist;
Von welchem Typ sind T_soll und T_ist?
Dirk B. schrieb:> Das ist dann auch übersichtlicher.>> Das sollte der Optimizer regeln.
Nein, der macht den Code nicht übersichtlicher ;-)
Und da fangen vermutlich die Probleme an. Die vermischst hier nicht nur
signed und unsigned, sondern auch noch 8Bit und 32Bit (und je nach Proz.
auch noch 16Bit) und hoffst bei dem ganzen das der Compiler schon von
sich aus den besten davon aussucht. Irrtum...:-)
Recht gemeine Falle ist, dass zuerst der gesamte Ausdruck berechnet wird
und dann erst die Zuweisung (ggf. mit erf. cast) zur linken Seite
erfolgt und noch so einige Fallen die du dir durch dein wildes
Typendurcheinander eingebaut hast. Stichwort zum suchen/lernen ist hier
unter anderem "integer promotion".
-
https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules
- https://en.cppreference.com/w/c/language/conversion
- und noch sehr viel mehr...
Irgend W. schrieb:> Und da fangen vermutlich die Probleme an.
Dann sag doch mal ganz konkret, wo da deiner Meinung nach das Problem
stecken soll.
Oliver
A. S. schrieb:> Ups, jetzt seh ich es: deine IFS gelten nur für < und >, nicht für==> oder >=
So sehe ich das auch. Wenn P*e den Wert 65535 oder -65535 annimmt, dann
wird P_Teil gar nicht gesetzt.
65535 ist eine Integer Konstante - beim AVR 16 Bit. Es wundert mich,
dass der Compiler nicht meckert, hast Du mal auf die Warnings geschaut.
Du muss mit 65535l (für long) arbeiten...
Matthias Thiele schrieb:> 65535 ist eine Integer Konstante
Nein, ist es nicht. Das ist ein Integer Literal.
> Du muss mit 65535l (für long) arbeiten...
Nein, muss man nicht.
Oliver
Oliver S. schrieb:> Matthias Thiele schrieb:>> 65535 ist eine Integer Konstante>> Nein, ist es nicht. Das ist ein Integer Literal.
Doch, ist es. Die Bezeichnung dafür im C-Standard ist "integer
constant".
Rolf M. schrieb:> Doch, ist es. Die Bezeichnung dafür im C-Standard ist "integer> constant".
Selbst wenn, ist das constant was ganz anderes als das Schlüsselwort
const meint
Rolf M. schrieb:> Oliver S. schrieb:>> Matthias Thiele schrieb:>>> 65535 ist eine Integer Konstante>>>> Nein, ist es nicht. Das ist ein Integer Literal.>> Doch, ist es. Die Bezeichnung dafür im C-Standard ist "integer> constant".
Vermutlich deshalb hat C++ das in Integer literal umgetauft. Es ist eben
kein Integer, sondern ein literal, auch wenn’s C anders nennt.
Oliver
Oliver S. schrieb:> Rolf M. schrieb:>> Oliver S. schrieb:>>> Matthias Thiele schrieb:>>>> 65535 ist eine Integer Konstante>>>>>> Nein, ist es nicht. Das ist ein Integer Literal.>>>> Doch, ist es. Die Bezeichnung dafür im C-Standard ist "integer>> constant".>> Vermutlich deshalb hat C++ das in Integer literal umgetauft. Es ist eben> kein Integer, sondern ein literal, auch wenn’s C anders nennt.
Ich nehme an, du meinst "Konstante" statt "Integer".
Ein direkt als Zahl hingeschriebener Wert ist die einzige Art von echter
Konstante, die C kennt. Wie EAF schon schreibt, ist in C eine Variable,
die mit const definiert ist, keine Konstante. Das ist in C++ anders,
daher musste man dort den Begriff ändern.
Du kannst gerne am Begriff Haare spalten, ob das dem Fragensteller
weiter hilft, ist eine andere Frage.
Die Arduino Referenz sagt eindeutig, dass ein int bei den ATmega 16 Bit
breit ist. Und ein literal nur aus Ziffern ist ein int Wert. Wenn man
ein long Wert haben will, gehört ein L (oder l) hinten dran.
Matthias T. schrieb:> Die Arduino Referenz sagt eindeutig
Die ist irrelevant!
Spannender ist, wie der Compiler es damit hält.
Und das ist wohldefiniert.
Entspricht aber scheinbar nicht deiner Vorstellung...
Meine Vorstellung ist hier nicht relevant. Was der Standard sagt ist
entscheidend. Und ein Overflow in einem Literal ist undefined behavior.
Und wie ich vermutet hatte, der Arduino Compiler liefert eine Warning:
warning: overflow in implicit constant conversion [-Woverflow]
int x = -655365;
Matthias T. schrieb:> Und ein Overflow in einem Literal ist undefined behavior.
Ähhhmm....
Was ist denn ein "Overflow in einem Literal"?
Davon habe ich ja noch nie gehört....
"undefined behavior" da kann ich nichts zu sagen, da ich nicht weiß Was
ein "Overflow in einem Literal" ist.
Sage es mir, bitte...
Matthias T. schrieb:> warning: overflow in implicit constant conversion [-Woverflow]> int x = -655365;
Das ist übrigens KEIN Literal Überlauf, sondern eine verlustbehaftete
Konvertierung.
EAF schrieb:>> Matthias T. schrieb:>> warning: overflow in implicit constant conversion [-Woverflow]>> int x = -655365;>> Das ist übrigens KEIN Literal Überlauf, sondern eine verlustbehaftete> Konvertierung.
Wie bereits geschrieben - Du kannst bei den Begriffen beliebig viele
Haare Spalten aber dem OP hilft das nicht weiter. Entscheidend ist, dass
er den Bereich eines 16 Bit Integer verlassen hat und sich wundert, dass
es nicht funktioniert.
Ob ein Literal einen Typ hat oder nicht ist eine etwas akademische
Diskussion. Ich verstehe den Standard so, dass ein numerisches Literal
dieser Art ein Integer (und kein Long) Typ besitzt. Natürlich kann man
argumentieren, dass das Literal selber gar keinen Typ besitzt und erst
bei der konkreten Verwendung in etwas konvertiert wird. Aber am Ende
kommt das gleiche dabei raus - in diesem Fall undefiniertes Verhalten
wegen eines Überlaufs.
Matthias T. schrieb:> Ob ein Literal einen Typ hat oder nicht ist eine etwas akademische> Diskussion.
Nein, das ist in der Sprachdefinition genau festgelegt.
> Ich verstehe den Standard so, dass ein numerisches Literal> dieser Art ein Integer (und kein Long) Typ besitzt.
Der Typ eines Integer-Literals wird passend zu seinem Wert festgelegt.
> Natürlich kann man argumentieren, dass das Literal selber gar keinen> Typ besitzt
Auch das ist genau festgelegt: Typlos ist es nur dann, wenn wenn der
Wert durch keinen der verfügbaren Integer-typen dargestellt werden kann.
Einfach mal nachlesen.
Matthias T. schrieb:> Natürlich kann man> argumentieren, dass das Literal selber gar keinen Typ besitzt und erst> bei der konkreten Verwendung in etwas konvertiert wird.Yalu X. schrieb:> Einfach mal nachlesen.
Ihm hat seine eigenen Vorstellungen und Begrifflichkeiten.
Ihm will gar nicht kommunizieren.
Und irgendwelche Sprach/Compiler Realitäten interessieren ihm auch
nicht.
Matthias T. schrieb:> Entscheidend ist, dass> er den Bereich eines 16 Bit Integer verlassen hat und sich wundert, dass> es nicht funktioniert.
Wo wir denn im Beispiel vom TO mit (16-Bit) int gerechnet?
Der ausschlaggebende Typ ist int32_t
Matthias T. schrieb:> Meine Vorstellung ist hier nicht relevant. Was der Standard sagt ist> entscheidend.
Ja, aber wenn man dir sagt, was im Standard steht, tust du das als
Haarspalterei ab und behauptest stattdessen etwas anderes, das da gar
nicht steht.
> Und ein Overflow in einem Literal ist undefined behavior.
Nein. Nochmal: Im C-Standard gibt es keine integer literals, und einen
Overflow bei Integer-Konstanten gibt es auch nicht.
Yalu X. schrieb:> Einfach mal nachlesen.
Ja, z.B. im letzten Draft von C18:
https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf
Siehe dort Kapitel 6.4.4.1 "Integer constants".
Matthias T. schrieb:> Aber am Ende kommt das gleiche dabei raus - in diesem Fall> undefiniertes Verhalten wegen eines Überlaufs
Ernste Frage: hast Du verstanden, dass Dein Beispiel fehlerhaft war?
Zumindest im Bezug auf den Code des TO?
Dass hingeschriebene Zahlen einen Typ haben und beim Rechnen damit
Überlaufe möglich sind, ist ja richtig. 3x3000O ist nicht 90000. Und
0xFFFF etwas anderes als 65535. Ist verwirrend, wenn man erstmals darauf
stößt. Kommt aber beim TO nicht vor.
Kernigham und Ritchie sind mir leider nicht zur Hilfe gekommen. Integer
Konstanten (und ja, die beiden nennen sie constants und bestehen nicht
auf literals) werden automatisch zu unsigned int und auch zu long, wenn
sie nicht in ein int passen - schon immer. Damit ist der modifier L
scheinbar nur Dekoration. Vermutlich habe ich die falsche Information
von einem Compiler, der nicht complient war.
Matthias T. schrieb:> werden automatisch zu unsigned int und auch zu long, wenn> sie nicht in ein int passen - schon immer.
Nein, nicht schon immer. Unsigned gabs bei dezimalen Integer Constants
nur bis C99, danach werden das immer signed integer Typen.
Oliver
Matthias T. schrieb:> scheinbar nur Dekoration
Nein, eben nicht: damit man sie in Rechnungen wie 3x30.000 verwenden
kann, ist ein L (für eine der beiden Zahlen zumindest) erforderlich.
Und (0xffff+1 == 65535+1) ist nur dann true, wenn links ein L oder bei
65535 ein U steht. Dass im zweiten Fall beide Seiten 0 ergeben, macht es
nicht einfacher
(Alle Beispiele mit 16 Bit ints)
Kernigham & Ritchie schrieb:> A. S. schrieb:>> Und 0xFFFF etwas anderes als 65535.> ??? ??? ??? ??? ??? ??? ??? ??? ??? ???
0xffff ist unsigned int.
65535 ist long int.
Kernigham & Ritchie schrieb:> Hex und Dezimal sind nur andere Darstellungsformen zum Lesen. Warum sind> das unterschiedliche Datentypen?
Weil C das eben so festlegt. Kann man im von mir oben verlinkten
Dokument auf Seite 46 nachlesen.
Kernigham & Ritchie schrieb:> Dafür fehlt mir jede Art der Logik.
Ich will das jetzt gar nicht schönreden. Aber ich brauche Hex-Zahlen >
0x7fff (kleinere sind egal) meist für Masken, Bit-Felder oder
Schiebeoperationen und die sind meist uint. Während Dezimalzahlen oft
int sind.
Das eigentliche Problem liegt m.E. nicht bei den Literal-Überläufen (die
Warnungen sind ja meist an), sondern z.B. bei
1
inti=-1;
2
unsignedintu=4;
3
4
if(i<u){doit();}/*warum wird doit nie aufgerufen ???*/
A. S. schrieb:> Das eigentliche Problem liegt m.E. nicht bei den Literal-Überläufen (die> Warnungen sind ja meist an), sondern z.B. bei> int i=-1;> unsigned int u = 4;> if(i<u) {doit();} /*warum wird doit nie aufgerufen ???*/
Mein C warnt mich!
Pavel (pavelpalavel)
>ich möchte einen P-Regler programmieren und bin gerade zu dumm dafür.>Hier mein Code:
Du solltest Rechenzeit sparen und die Multiplikation nur einmal rechnen.
Für einen guten Codestil noch ein Tipp: Keine "Magic Numbers".
A. S. schrieb:> Kernigham & Ritchie schrieb:>> Dafür fehlt mir jede Art der Logik.>> Ich will das jetzt gar nicht schönreden. Aber ich brauche Hex-Zahlen >> 0x7fff (kleinere sind egal) meist für Masken, Bit-Felder oder> Schiebeoperationen und die sind meist uint.
Warum sind kleinere egal? 0x5000 << 1 ergibt undefiniertes Verhalten.
> Während Dezimalzahlen oft int sind.
Vor allem: Will man wirklich, dass 30000 vorzeichenlos ist, 40000 aber
vorzeichenbehaftet? Das fände ich eher nicht sehr intuitiv.
Rolf M. schrieb:> Warum sind kleinere egal? 0x5000 << 1 ergibt undefiniertes Verhalten.>> Vor allem: Will man wirklich, dass 30000 vorzeichenlos ist, 40000 aber> vorzeichenbehaftet? Das fände ich eher nicht sehr intuitiv.
Natürlich will man keines davon.
Das Typsystem von C ist komplett kaputt. Von vorne bis hinten.
Unrettbar.
> So macht es die KI (Gast)
Hast du das mit ChatGPT gemacht?
Wäre ziemlich beeindruckend.
Vielleicht kannst du ihr noch sagen, dass sie den Regler mit "int" statt
"float" machen soll ...
Gerd schrieb:> Wäre ziemlich beeindruckend.
Solche einfachen Regler gibt es zu Hauf im Internet.
Ich finde das weniger beeindruckend, wenn eine "KI" aus dieser Menge
sich eine "eigene" Lösung zurechtraubkopieren kann.
Ist und bleibt eine gut versteckte Urheberrechtsverletzung.
>ChatGPT mit Integer
Finde ich schon beeindruckend. Könntest du eventuell das Chat-Protokoll
als PDF anhängen? Mich würde mal interessieren, wie man die KI geschickt
fragt.
A. S. schrieb:>> scheinbar nur Dekoration>> Nein, eben nicht: damit man sie in Rechnungen wie 3x30.000 verwenden> kann, ist ein L (für eine der beiden Zahlen zumindest) erforderlich.
Prinzipiell schon. Allerdings werten alle Compiler, die ich unter
"Compiler Explorer" getestet habe, constant expressions schon zur
compile time aus und benötigen das L ebenfalls nicht. In der
Dokumentation zum Microsoft Compiler steht auch ausdrücklich, dass
constant expressions immer zur compile time ausgewertet werden (was ja
auch Sinn ergibt).
Ich weiß aber nicht, ob sich der Standard dazu äußert...
Matthias T. schrieb:> A. S. schrieb:>>> scheinbar nur Dekoration>>>> Nein, eben nicht: damit man sie in Rechnungen wie 3x30.000 verwenden>> kann, ist ein L (für eine der beiden Zahlen zumindest) erforderlich.>> Prinzipiell schon. Allerdings werten alle Compiler, die ich unter> "Compiler Explorer" getestet habe, constant expressions schon zur> compile time aus und benötigen das L ebenfalls nicht.
Die Auswertung zur Compile-Zeit ändert aber am (falschen) Ergebnis
nichts.
So macht es die KI schrieb:> ChatGPT mit Integer
Dass der Code durch eine KI generiert wurde, ist schon beeindruckend. Er
ist aber weitgehend nutzlos, weil er etliche Fehler enthält. Diese zu
finden und zu korrigieren ist mindestens so aufwendig, als den Code
einfach neu zu schreiben (so ein P-Regler ist ja keine Raketentechnik).
Zeile 12:
1
returnKp*error/100;
Das Produkt 100 * 500 = 50000 führt zum Überlauf (INT_MAX = 32767). Der
gesamte Ausdruck muss in int32_t gerechnet werden, das Ergebnis kann
wieder in int gecastet werden. Der Rückgabewert ist dann 100 * 500 / 100
= 500.
Zeile 21:
1
TCCR1A|=(1<<WGM10)|(1<<WGM11);// Fast PWM mode
WGM10 darf nicht gesetzt werden, da ICR1 als TOP-Wert des Timers
verwendet werden soll (s. Zeile 26).
Zeile 37:
1
OCR1A=control_signal*PWM_RANGE/100;
Diese Zeile setzt voraus, dass control_signal auf [0..100] (in der
float-Version auf [0..1.0]) normiert ist. Eine solche Normierung findet
aber nirgends im Programm statt. Konkret ist – nachdem der Fehler in
Zeile 12 korrigiert wurde – control_signal = 500, damit ist das Ergebnis
des Ausdrucks ebenfalls 500 und damit größer als PWM_RANGE. PWM_RANGE
wird deswegen seinem Namen nicht gerecht und ist einfach nur ein
weiterer Skalierungsfaktor.
Da ICR1 (Zeile 26) maximal 20 MHz ÷ 500 ÷ 100 = 400 sein kann, wird der
Timer den Wert von OCR1A = 500 nie erreichen. Die Regelung verlässt
damit für OCR1A > 400 den linearen Bereich. Das kann man zwar
akzeptieren, aber schön ist das nicht und sollte höchstens in
Ausnahmefällen (bspw. beim Starten des Systems, wenn es noch nicht
eingeschwungen ist) geschehen.
Da hat die KI offensichtlich aus mehreren, möglicherweise ebenfalls
fehlerhaften Code-Fragmenten aus dem Web etwas zusammengestückelt. Dass
die KI den Code nicht wirklich versteht, dürfte klar sein.
Yalu X. schrieb:> Er ist aber weitgehend nutzlos, weil er zu etliche Fehler enthält.
Natürlich. Das sind ja auch nur Codestücke aus tausenden Open Source
Programmen.
Ein Verständnis für Algorithmus, Sprache und Mikrocontroller liegt hier
seitens "KI" ja nicht vor.
Ich kann mir zwar durchaus vorstellen, dass Implementationen von
Algorithmen in Zukunft in einigen Bereichen mit solchen "KI"-Generatoren
generiert werden.
Aber das sehe ich eigentlich grundsätzlich nur für Programmiersprachen,
die extra dafür gemacht sind und wo solche primitiven Fehler wie
Integerüberläufe oder Typfehler von der Sprache selbst verhindert
werden.
Es ist nutzlos ein Programm zu schreiben oder sich schreiben zu lassen,
das fehlerhaft ist. Und es ist fast genau so nutzlos, wenn man keinerlei
Aussage über dessen Fehlerhaftigkeit hat.
Nicht ohne Grund haben seriöse Machine-Learning-Einsatzgebiete auch
immer noch Plausibilisierungen und Fehlerbehandlungen. Entweder
nachgeschaltet klassisch implementiert, oder teilweise vom Netz selbst
generiert (Softmax), oder oft eine Kombination aus beidem.
tl;dr
Dahingeklatschter generierter Code ist nutzlos.
Wenn man eine "KI" nach etwas fragt, dann gibt sie immer eine Antwort.
Die Kunst ist herauszufinden, wann sie falsch liegt.
Der Spiegel hat gerade einen Artikel veröffentlicht, wonach KI Systeme
wie ChatGPT womöglich bald die Google Suchmaschine ersetzten könnten.
Vorteil sei vor allen das Textverständnis der KI. Mann müsse seine
Suchanfragen nicht mehr Google-Konform formulieren, sondern kann
natürliche Sprache verwenden.
https://www.spiegel.de/netzwelt/netzpolitik/bessere-treffer-durch-chatgpt-das-ende-von-google-wie-wir-es-kannten-kolumne-a-77820af6-51d7-4c03-b822-cf93094fd709
Ich denke, dass der Autor folgende erhebliche Nachteile außer Acht
gelassen hat:
1) Die KI ist nicht imstande, ihre Quellen zu nennen.
2) Die KI Antwortet immer überzeugend, selbst wenn sie Null Ahnung hat.
3) Die KI gibt immer nur eine Antwort.
4) Die Traningsdaten sind nicht aktuell und werden es wohl auch nie
sein. Würde die KI das ganze Internet direkt (ohne manuelle Filterung)
verwenden, dann würde sie viel Bullshit nachplappern.
Yalu X. schrieb:>> compile time aus und benötigen das L ebenfalls nicht.>> Die Auswertung zur Compile-Zeit ändert aber am (falschen) Ergebnis> nichts.
Bei der Auswertung zur Compile-Zeit ist das Ergebnis korrekt. Der
Compiler erkennt, dass er den int Bereich verlässt und wechselt
automatisch auf long (oder er rechnet diese Ausdrücke intern immer in
long). Zumindest alle Compiler, die ich getestet habe. Ob der Standard
das fordert oder ob es vielleicht obskure Compiler gibt, die es nicht
tun, ist mir nicht bekannt.
So macht es die KI schrieb:> Proportionalregler in ansi c code>> Bitte für Atmel AVR Controller>> Bitte mit Integer statt float….
Liest sich wie INTERCAL, wo "please" ein Schlüsselwort ist, weil man ja
hoflich zum Compiler sein soll:
https://de.wikipedia.org/wiki/INTERCAL
Stefan F. schrieb:> 1) Die KI ist nicht imstande, ihre Quellen zu nennen.
Es ist jedefalls extrem aufwändig und auch nicht immer im Einzelfall
zweifelsfrei möglich.
> 2) Die KI Antwortet immer überzeugend, selbst wenn sie Null Ahnung hat.
Ja. Die einfachste Implementierung einer "KI" ohne Plausibilisierung tut
genau das.
Und das ist auch ihr größtes Problem. Dieses Problem macht die Ausgabe
nutzlos.
Meine Hochachtung vor dem, was die Wissenschaftler und Ingenieure hier
geschaffen haben.
Aber das ist erst ein ganz ganz ganz kleiner Teil einer allgemeinen und
nutzbaren Antwortmaschine.
> 3) Die KI gibt immer nur eine Antwort.
Das würde ich so nicht unterschreiben.
So macht es die KI schrieb:> Proportionalregler in ansi c code>> Bitte für Atmel AVR Controller>> Bitte mit Integer statt float….
Ja.
Das ist dein Programm.
Du hast dein Programm nicht in C formuliert, sondern in Deutsch.
Das kann natürlich sinnvoll sein. Schließlich ist es eine Erhebung in
eine höhere Hochsprache.
Aber es muss nicht sinnvoll sein. Ziemlich sicher sogar ist es oft nicht
sinnvoll, weil sich in der Sprache Deutsch viele Dinge gar nicht
eindeutig formulieren lassen.
Jeder, der einmal Anforderungsengineering gemacht hat, wird das wissen.
Matthias T. schrieb:> Bei der Auswertung zur Compile-Zeit ist das Ergebnis korrekt. Der> Compiler erkennt, dass er den int Bereich verlässt und wechselt> automatisch auf long
Wieder nur ein Ausdruck dieses völlig defekten Typsystems und ein
weiterer Sargnagel für das C-Ökosystem.
MaWin schrieb:> Yalu X. schrieb:>> Er ist aber weitgehend nutzlos, weil er zu etliche Fehler enthält.>> Natürlich. Das sind ja auch nur Codestücke aus tausenden Open Source> Programmen.> Ein Verständnis für Algorithmus, Sprache und Mikrocontroller liegt hier> seitens "KI" ja nicht vor.
Würd mich interessieren, wie die "KI" das selbst bewertet hat. Um die
87%?! :DDD
J. S. schrieb:> Man kann die KI auf Fehler hinweisen und die schafft es auch die zu> korrigieren
Aber sobald du einen neuen Chat beginnst (selbst ohne dich auszuloggen)
hat sie deine Korrektur schon wieder vergessen.
Du frage dabei ist: Wie kann die KI deine Korrektur bewerten?
Man könnte der KI 20x sagen, dass Menschen aus bestimmten Regionen wegen
einem Gendefekt geistig behindert seien. Das könnte sogar wahr sein. Die
Entwickler werden wahrscheinlich dafür sorgen, dass sie KI solche
Aussagen trotzdem nicht übernimmt. Dann ich sie aber noch weniger
neutral, als wenn sie bei den Fakten bleiben würde. Ein fieses Dilemma.
J. S. schrieb:> Man kann die KI auf Fehler hinweisen und die schafft es auch die zu> korrigieren
Das ist ja nur eine Rekursionsschleife, in der du dein in Deutsch
geschriebenes Programm konkretisierst und Zweideutigkeiten entfernst,
bis dein Compiler (hier ChatGPT) dir das korrekte Kompilat ausgibt.
Fühlt sich an wie zurückversetzt in die Anfänge der Compilertechnik vor
Jahrzehnten.
Matthias T. schrieb:> Yalu X. schrieb:>>> compile time aus und benötigen das L ebenfalls nicht.>>>> Die Auswertung zur Compile-Zeit ändert aber am (falschen) Ergebnis>> nichts.>> Bei der Auswertung zur Compile-Zeit ist das Ergebnis korrekt. Der> Compiler erkennt, dass er den int Bereich verlässt und wechselt> automatisch auf long (oder er rechnet diese Ausdrücke intern immer in> long).
Mit welchem fehlerhaften Compiler hast du das getestet?
Edit:
3*30000 auf einem 16-Bit-System ist ohnehin undefined, da darf der
Compiler ein beliebiges Ergebnis liefern, also bspw. auch 90000 (wobei
das aber wahrscheinlich kein real existierende Compiler tun wird). In
diesem Fall ist nicht der Compiler, sondern der Quellcode mit dem
3*30000 fehlerhaft.
Nehmen wir als besseres Beispiel 3u*30000u (Berechnung erfolgt in
unsigned int), dann ist auf einem 16-Bit-System das einzige
standardkonforme Ergebnis 24464 und nicht etwa 90000.
Teo D. schrieb:>> Ein Verständnis für Algorithmus, Sprache und Mikrocontroller liegt hier>> seitens "KI" ja nicht vor.>> Würd mich interessieren, wie die "KI" das selbst bewertet hat. Um die> 87%?! :DDD
Das ist in der Tat gar nicht so eine schlechte Idee und solche Techniken
werden ja bereits eingesetzt. Man kann z.B. mit Softmax eine Aussage
darüber erhalten, "wie sicher" sich ein einfaches MLP-Netz mit seiner
Antwort ist, oder ob das Netz "zweifelt".
Eine Aussage darüber zu bekommen, wie sicher sich ChatGPT ist und wie
tief es "verstanden" hat worüber es redet, ist die eigentliche knifflige
Aufgabe, die es zu lösen gilt.
Yalu X. schrieb:>> Bei der Auswertung zur Compile-Zeit ist das Ergebnis korrekt. Der>> Compiler erkennt, dass er den int Bereich verlässt und wechselt>> automatisch auf long (oder er rechnet diese Ausdrücke intern immer in>> long).>> Mit welchem fehlerhaften Compiler hast du das getestet?>> Edit:>> 3*30000 auf einem 16-Bit-System ist ohnehin undefined, da darf der> Compiler ein beliebiges Ergebnis liefern, also bspw. auch 90000. In> diesem Fall ist nicht der Compiler, sondern der Quellcode mit dem> 3*30000 fehlerhaft.
Das hatte ich bis gestern auch geglaubt und in meinen eigenen Quellen
würde ich auf jeden Fall (und werde es weiterhin auch tun) mit 30000L
arbeiten. Getestet habe ich mit verschiedenen 16 Bit GCC und 16 MSVC -
das ist beim Compiler Explorer eine Fragen von wenigen Maus Klicks. Die
Zahl der 16 Bit Compiler ist allerdings überschaubar.
> ...das einzige standardkonforme Ergebnis 24464 und nicht etwa 90000.
Wenn das Ziel ein (16 Bit) int ist - ja. Wenn das Ziel ein long ist,
dann ist es nicht so einfach. Für eine einzelne Konstante steht schon
bei K&R ausdrücklich, dass der Compiler automatisch erst auf U und dann
auf L wechselt, wenn es notwendig ist. Warum sollte er es bei konstanten
Ausdrücken nicht dürfen? Da bin ich Neugierig auf die Stelle im
Standard, die es verbietet.
MaWin schrieb:> Du hast dein Programm nicht in C formuliert, sondern in Deutsch.
Und wie würde es aussehen, wenn man in eine KI C-Code reinfüttert und
gerne eine Assembler-Ausgabe hätte, d.h. man möchte den Code
compilieren?
Nach aktuellem Ansatz würde man i.W. Compiler-generierten Code als
Trainingsdaten verwenden. Mal angenommen, der Compiler liefert immer
korrekten Code (d.h. für alle spezifizierten Eingaben) und das
C-Programm ist sinnvoll (d.h. nicht UB oder so).
Würde die KI immer korrekte Ausgaben (Asm-Code) liefern?
Die Antwort ist wohl "nein". In diesem Falle: Wie würde man korrekte von
inkorrekten Ausgaben unterscheiden? Mit klassichen Compilern hat man
dieses Prolbem ja nicht, weil ein Compiler ja "per Design" korrekten
Code erzeugt, Compiler-Bugs mal außen vorgelassen.
Moderne Compiler sind überaus komplex und erzeugen Code, der oft weit
entfernt von optimal ist, egal nach welcher Metrik bemessen. Eine KI
würde all diese Schwächen vom Compiler erlernen.
Gibt es eine Möglichkeit, der KI den Sprachstandard beizubringen? Dite
Hardware-Beschreibung? Oder gibt es andere Möglichkeiten, dass der
erzeugte Code "korrekt per Design" ist?
Oliver S. schrieb:> Yalu X. schrieb:>> 3*30000 auf einem 16-Bit-System ist ohnehin undefined>> Warum?>> Oliver
Weil 30000 dezimal ist, dass ist signed und signed Überläufe sind UB.
Nochmal zurück zum Thema.
Weiß jemand warum das so völlig verrückt ohne Logik festgelegt wurde?
0xFFFF >> HEX ist uint16_t
65535 >> DEZ ist int32_t
Johann L. schrieb:> Würde die KI immer korrekte Ausgaben (Asm-Code) liefern?
Eine "KI" gibt nie eine 100% korrekte Antwort.
Machine Learning hat mehr die Eigenschaften einer analogen Schaltung,
als die einer eindeutigen digitalen Rechnung.
Die Antwort ist immer mit einem Fehler behaftet.
Das ist eine der wichtigsten Grundlagen, wie man bei "KI" und ML
verstehen muss.
Leider geben populäre "KI"-Tools wie ChatGPT diese Fehlerabschätzung
nicht an den Nutzer aus. Entweder, weil die Abschätzung gar nicht
stattfindet, oder weil das den Nutzer ja nur verwirren würde (tm).
Johann L. schrieb:> Die Antwort ist wohl "nein". In diesem Falle: Wie würde man korrekte von> inkorrekten Ausgaben unterscheiden? Mit klassichen Compilern hat man> dieses Prolbem ja nicht, weil ein Compiler ja "per Design" korrekten> Code erzeugt, Compiler-Bugs mal außen vorgelassen.
Ja, genau deshalb ist es nicht sinnvoll ein Programm mit einer "KI" zu
kompilieren. Jedenfalls dann, wenn man den Anspruch hat, dass das
Ergebnis 100% korrekt sein muss.
Machine Learning ist dann sinnvoll, wenn man einen gewissen Fehler in
den generierten Daten tolerieren kann.
Und das mag bei einem generierten C-Programm ja in gewissem Rahmen
durchaus tolerierbar sein.
Aber der derzeitige Stand ist davon extrem weit entfernt.
Selbst ein Assembly-Code lässt ja noch Spielraum für "Korrektheit".
Ein etwas langsamer laufendes Programm kann ja immer noch korrekt sein.
Aber der Spielraum ist in diesem Fall wohl eher sehr klein.
Johann L. schrieb:> Gibt es eine Möglichkeit, der KI den Sprachstandard beizubringen? Dite> Hardware-Beschreibung? Oder gibt es andere Möglichkeiten, dass der> erzeugte Code "korrekt per Design" ist?
Da eine KI auch nur von jemanden programmiert wird, wird es nie eine
echte KI geben. Der Begriff KI allein ist schon total bescheuert. Diese
Selbstlernmechanismen sind vom Programmierer vorgegeben. Von ganz
alleine kann eine KI nichts lernen. Außerdem werden noch unzählige
Trainingsdaten hinterlegt. Wer weiß welche ungenügenden Trainingsdaten
die Twitter KI hatte wo sie Bilder eines Raketenstarts falsch
eingeordnet hatte. Was auch nur ein Beweis ist das eine KI einfach nur
dumm ist und nur einen Abgleich machen kann. Nur was daran ist KI?
Irgendwelche Differenzen bilden? Der Begriff KI muss für zu viel Mist
herhalten. Wenn es eine wirklich echte KI gebe müßte man davor Angst
haben, denn dann hat man keine Kontrolle darüber.
Johann L. schrieb:> Gibt es eine Möglichkeit, der KI den Sprachstandard beizubringen? Dite> Hardware-Beschreibung? Oder gibt es andere Möglichkeiten, dass der> erzeugte Code "korrekt per Design" ist?
Ich könnte mir vorstellen, dass wir in nicht allzu ferner Zukunft
einzelne Optimierersteps sehen werden, die mit "KI" / ML realisiert
wurden.
Wenn man so einen Optimierer von außen stark beschränkt und
kontrolliert/plausibilisiert, dann könnte das eventuell nützlich sein.
(Hardwarehersteller wie Intel/AMD sollen ja solche ML-basierten
Optimierer für die Hardwareauslegung nutzen)
Auf der anderen Seite ist hier mit klassischen Methoden auch heute noch
mehr rauszuholen.
Denn die Regel, dass man keine "KI" nutzen sollte, wenn das Problem sich
klassisch lösen lässt, die gilt ja immer.
Kernigham & Ritchie schrieb:> Weiß jemand warum das so völlig verrückt ohne Logik festgelegt wurde?> 0xFFFF >> HEX ist uint16_t> 65535 >> DEZ ist int32_t
Vielleicht hatte sich der Erfinder dabei gedacht, dass Hex Zahlen bei
ihm normalwerweise nie ein Vorzeichen haben, daher das "u". Und so
passen sie in einen int16, also uint16.
In C ist vieles unlogisch. Das muss man einfach hinnehmen, oder in
anderen Sprachen programmieren. Aber glaube mir: Auch da ist nicht alles
für jeden Menschen logisch.
Es ist Aufgabe des Programmierers, die Brücke zwischen Mensch (ich will
...) und Maschine (ich kann ...) zu schlagen.
Kernigham & Ritchie schrieb:> Weiß jemand warum das so völlig verrückt ohne Logik festgelegt wurde?> 0xFFFF >> HEX ist uint16_t> 65535 >> DEZ ist int32_t
Genau diese Konstellation erscheint mir eigentlich sehr sinnvoll. Wie
oben schon geschrieben wurde, arbeitet man mit Hex-Werten eher in
vorzeichenlosem Kontext, bei Dezimal-Werten ist es gut, wenn die
Signedness nicht vom Wert abhängt (also z.B. 30000 signed und 40000
unsigned).
Was mir nur recht willkürlich erscheint ist, dass bei Hex-Zahlen eben
doch auch signed verwendet wird, denn 0x7FFF wäre z.B. int16_t.
Kernigham & Ritchie schrieb:> Da eine KI auch nur von jemanden programmiert wird
Eine "KI", also ein Machine Learning Algorithmus ist im Kern recht
einfach. Der Programmcode ist nicht das, wo die Leistung und die
Innovation drin steckt.
Kernigham & Ritchie schrieb:> Diese Selbstlernmechanismen sind vom Programmierer vorgegeben
Ja. Die Mechanismen, Architektur, Hyperparameter und Datensätze geben
die Grenzen des Möglichen vor.
Die eigentliche "Magie" findet dann aber im Lernprozess selbst statt.
Dieser Prozess als Ganzes wird vom Menschen dann in der Regel nicht mehr
komplett verstanden. Aus vielen Gründen. Darunter z.B. eine hohe
Multidimentionalität, die man sich nicht mehr bildlich vorstellen kann.
Es gibt dann Methoden, die einem dabei helfen zu verstehen, was die "KI"
gelernt hat. Aber das ist alles auch nur sehr beschränkt und gezielt
möglich. Nicht allgemein.
Die "KI" ist im eingelernten Zustand eben nicht von einem Menschen im
Detail vorgegeben.
Das wird schon alleine dadurch klar, das zwei Netz-Instanzen mit
ziemlich verschiedenen Gewichten ( = die Betriebsparameter) zu praktisch
identischen Ergebnissen kommen können.
Die Betriebsparameter der Netze starten in der Regel mit zufälligen
Werten vor dem Trainingslauf. D.h. nach jedem Trainingslauf sehen auch
die Parameter anders aus. Aber (!) die Gesamteigenschaften, also die
Ausgaben, der Netze unterscheiden sich kaum (wenn man seine
Hyperparameter, Architektur und so weiter im Griff hat).
Rolf M. schrieb:> Kernigham & Ritchie schrieb:>> Weiß jemand warum das so völlig verrückt ohne Logik festgelegt wurde?>> 0xFFFF >> HEX ist uint16_t>> 65535 >> DEZ ist int32_t>> Genau diese Konstellation erscheint mir eigentlich sehr sinnvoll. Wie> oben schon geschrieben wurde, arbeitet man mit Hex-Werten eher in> vorzeichenlosem Kontext, bei Dezimal-Werten ist es gut, wenn die> Signedness nicht vom Wert abhängt (also z.B. 30000 signed und 40000> unsigned).> Was mir nur recht willkürlich erscheint ist, dass bei Hex-Zahlen eben> doch auch signed verwendet wird, denn 0x7FFF wäre z.B. int16_t.
Soeben selbst getestet, stimmt. Bei sowas frage ich mich immer was das
soll. Programmieren hat für mich sehr viel mit Logik zu tun. Das hier
hat aber keine Logik mehr. Wenn man jeden Mist im Standard nachlesen
muss, weil jetzt auch noch Wertebereiche unterschiedlich behandelt
werden, dann macht das alles keinen Spass mehr. Das Ende vom Lied wird
sein man castet alles. Ob das sinnvoll ist? Und dann wundert man sich
das es so viele Programmfehler gibt die kaum entdeckt werden. Muss ein
C/C++ Programmierer das Standard-Draft auswendig lernen?
Die Einzigste Erklärung die ich habe ist, weil int der Default Typ ist
und 0x7FFF in ein int passst ist das noch int. Aber dann soll bitte
schön alles gleich behandelt werden. Ob man octal, binär, dezimal oder
hex schreibt sollte keinen Unterschied machen. Auf der einen Seite legt
das Gremium irgendwelche (un)logischen Standards fest. Und auf der
anderen Seite definieren sie UB auf alles worauf sie keine Lust haben.
So kommt mir das mittlerweile vor.
Aber gut wieder was gelernt, auch wenn mich das langsam anko....
Danke auch an Stefan und MaWin O.
Kernigham & Ritchie schrieb:> Muss ein C/C++ Programmierer das Standard-Draft auswendig lernen?
Sollte, ja. Ist aber eher unpraktisch.
Kernigham & Ritchie schrieb:> Auf der einen Seite legt> das Gremium irgendwelche (un)logischen Standards fest. Und auf der> anderen Seite definieren sie UB auf alles worauf sie keine Lust haben.> So kommt mir das mittlerweile vor.
Yepp
Kernigham & Ritchie schrieb:> Muss ein C/C++ Programmierer das Standard-Draft auswendig lernen?
Ja. Das muss man eigentlich tun.
Denn wenn man gegen den Standard verstößt, dann löst man oft genug UB
aus und dann hat man verloren. Von den Compilerentwicklern bekommt man
dann nur die Anweisung sich halt an den Standard zu halten.
Einer der vielen Gründe, weshalb C/C++ endlich ersetzt werden sollten.
MaWin O. schrieb:> Einer der vielen Gründe, weshalb C/C++ endlich ersetzt werden sollten.
Ganz genau. Sowas wie UB sollte es in einer Programmiersprache nicht
geben. Das zu fordernde Minimum für eine moderne Programmiersprache ist,
dass der Compiler sowas selber erkennt und eine Fehlermeldung
produziert. Alles darunter ist vollkommen indiskutabel.
c-hater schrieb:> Das zu fordernde Minimum für eine moderne Programmiersprache ist,> dass der Compiler sowas selber erkennt und eine Fehlermeldung> produziert.
UB muss es immer geben. Denn UB gibt es auch auf Hardwareebene.
Eine komplett UB-freie Sprache, die keinen "Notausgang" aus dieser
Situation bietet, kann kein Ersatz für C/C++ sein.
Aber eine moderne Programmiersprache sollte UB auf das absolut
Notwendigste einschränken. z.B. indem Bereiche, die ein Compiler nicht
als UB-frei beweisen kann, entsprechend vom Programmierer deutlich
markiert werden müssen.
Dass in C/C++ an jeder Ecke die UB lauern kann, wenn man den Standard
nicht auswendig kennt, ist einfach nicht mehr tragbar.
MaWin O. schrieb:> UB muss es immer geben. Denn UB gibt es auch auf Hardwareebene.
Ja, sicher. Dort sind sie aber dokumentiert und es gibt mindestens einen
Weg, zu einem defined behavior zu gelangen.
Außerdem spielt das im Kontext einer Hochsprache keine Rolle (sollte es
zumindest nicht spielen). Denn der einzige Sinn einer Hochsprache ist,
solche Details der Hardware zu abstrahieren. Kann sie das nicht, taugt
sie nix.
c-hater schrieb:> Ja, sicher. Dort sind sie aber dokumentiert und es gibt mindestens einen> Weg, zu einem defined behavior zu gelangen.
Das ist bei C/C++ auch ganz genau so.
Und das ist genau das Problem.
Wer sich nicht an die Doku hält, wird nicht freundlich ermahnt, sondern
streng abgestraft.
c-hater schrieb:> Denn der einzige Sinn einer Hochsprache ist,> solche Details der Hardware zu abstrahieren. Kann sie das nicht, taugt> sie nix.
Es gibt natürlich viele Sprachen ohne UB. Aber die meisten davon sind
nicht für hardwarenahe Software verwendbar und sind somit kein Ersatz
für C/C++.
Wer nicht mit Rohzeigern hantieren kann, kann nicht auf Hardware
zugreifen.
Wer nicht mit handkodiertem ASM kommunizieren kann, kann keines der
notwendigen Basisprimitive implementieren.
etc, etc...
Eine Sprache komplett ohne UB und ohne eine explizite Möglichkeit
diesen garantierten kein-UB-Regeln zu entkommen, kann kein Ersatz für
C/C++ sein.
MaWin O. schrieb:> Dass in C/C++ an jeder Ecke die UB lauern kann, wenn man den Standard> nicht auswendig kennt, ist einfach nicht mehr tragbar.
UB in C geht ja noch, aber in C++ gibt es ein neues Leckerli:
"Ill-formed, [no] diagnostics required"
MaWin O. schrieb:> Es gibt natürlich viele Sprachen ohne UB. Aber die meisten davon sind> nicht für hardwarenahe Software verwendbar und sind somit kein Ersatz> für C/C++.
OK. Das Problem ist also im Kern, dass C/C++ die Eierlegende
Wollmilchsau sein soll. (und damit naturgemäß scheitert)
Genau so nehme ich das auch: hardwarenahes passiert in Asm, alles
darüber mit RICHTIGEN Hochsprachen. No need for C/C++.
> Wer nicht mit Rohzeigern hantieren kann, kann nicht auf Hardware> zugreifen.> Wer nicht mit handkodiertem ASM kommunizieren kann, kann keines der> notwendigen Basisprimitive implementieren.
All das geht auch mit echten Hochsprachen. Aus der unsäglichen (aber
leider auch nicht mehr änderbaren) Historie resultiert nur, dass man
dafür typisch das C-ABI benutzen muß, auch wenn kein bissel C-Code
involviert ist...
It's a shame...
c-hater schrieb:>> Wer nicht mit Rohzeigern hantieren kann, kann nicht auf Hardware>> zugreifen.>> Wer nicht mit handkodiertem ASM kommunizieren kann, kann keines der>> notwendigen Basisprimitive implementieren.>> All das geht auch mit echten Hochsprachen.
Aha.
Wie gehen denn Rohpointer garantiert ohne UB?
Und wie führe ich Asm-Code so aus, dass der Compiler die Abwesenheit von
UB gleich erkennt und ich ihm das nicht sagen muss?
Richtig. Beides geht nicht.
Deshalb braucht ein C/C++ Ersatz immer die Möglichkeit die UB-Freiheit
stellenweise, dort wo es notwendig ist, vom Programmierer attestieren zu
lassen. (Also das, was der Programmierer in C/C++ für das gesamte
Programm tun muss)
An diesen Stellen kann der Compiler prinzipbedingt die Abwesenheit von
UB nicht beweisen. Somit sind die Stellen nicht garantiert UB-frei.
Kernigham & Ritchie schrieb:> Und dann wundert man sich> das es so viele Programmfehler gibt die kaum entdeckt werden.
Nö, ich wundere mich nicht.
Wem float zu einfach ist, der muß eben jeden einzelnen Rechenschritt
darauf prüfen, daß das gewählte Ganzzahlformat nicht überschritten wird.
Auch das Ganzzahlen in C per default signed sind, ist auch nicht so
schwer zu merken.
Tja, und so kommt es, dass z.B. Windows vom ersten Tag bis heute
gespickt ist mit Bugs (und täglich werden es mehr), die die Mitarbeiter
von Microsoft nicht in den Griff bekommen, weil jeder eine andere
Vorstellung vom Programmieren hat und einen anderen Erfahrungs- und
Wissenstand, u.s.w.
Es muss doch völlig klar sein, dass die Menge der unbehobenen Bugs in
"professioneller" Software proportional zur Menge des Source-Codes inkl.
Libraries ist.
Peter D. schrieb:> Kernigham & Ritchie schrieb:>> Und dann wundert man sich>> das es so viele Programmfehler gibt die kaum entdeckt werden.>> Nö, ich wundere mich nicht.> Wem float zu einfach ist, der muß eben jeden einzelnen Rechenschritt> darauf prüfen, daß das gewählte Ganzzahlformat nicht überschritten wird.
Alles pauschal mit float zu erschlagen ist noch dümmer. Außerdem ging es
nicht um eigene Variablendefinitionen.
> Auch das Ganzzahlen in C per default signed sind, ist auch nicht so> schwer zu merken.
Das ist und war nicht das Thema. Bitte nochmal lesen.
Justin S. schrieb:> Es muss doch völlig klar sein, dass die Menge der unbehobenen Bugs in> "professioneller" Software proportional zur Menge des Source-Codes inkl.> Libraries ist.
Wieso sollte das völlig klar sein?
Das würde ja bedeuten, dass (1) alte Bugs nie behoben werden und (2)
neuer Code in etwa immer die gleiche Bugdichte hat.
Bei (2) gehe ich mit, aber (1) ist doch Unsinn.
Johann L. schrieb:> MaWin O. schrieb:>> Dass in C/C++ an jeder Ecke die UB lauern kann, wenn man den Standard>> nicht auswendig kennt, ist einfach nicht mehr tragbar.>> UB in C geht ja noch, aber in C++ gibt es ein neues Leckerli:>> "Ill-formed, [no] diagnostics required"
Wenn man das liest wird es immer mehr Multikulti .
https://stackoverflow.com/questions/22180312/difference-between-undefined-behavior-and-ill-formed-no-diagnostic-message-requ
Einerseits wird alles haarklein festgelegt, Standardantwort ist "lies
den Standard" und alles andere lässt man komplett offen. Nur was hat der
Programmierer von komplett offen? Man lässt den Programmierer im Stich.
Man sollte bei den Compilern bzw. in den Standard mehr Energie
reinstecken das weniger UB definiert ist anstatt immer neue
Sprachfeatures aus den Fingern zu saugen. Hat sich schon jemand gefragt
wo das noch hinführen soll mit dem C++? Es ist doch mittlerweile so das
kaum noch jemand die neuen Sprachfeatures versteht geschweige den
anwenden kann. Man müßte erstmal aufräumen anstatt immer höher
schneller weiter ausbauen. Ich habe grundsätzlich nichts gegen C++ aber
die Entwicklung stimmt nachdenklich und die Compilerqualität wird nicht
besser.
El Capitan schrieb:> Welche nutzt Du für AVR/ESP/STM32?
Alles, was er nicht in Assembler programmieren kann, programmiert er gar
nicht. Also fast alles, offenbar.
Kernigham & Ritchie schrieb:> in den Standard mehr Energie> reinstecken das weniger UB definiert ist
Das ist aber aus Rückwärtskompatibilitätsgründen kaum möglich.
Die Primitive um vernünftig, modern und garantiert UB-frei zu
programmieren, sind in C++ ja eigentlich fast alle vorhanden.
Nur der Compiler zwingt den Programmierer nicht sie zu nutzen.
Und er kann es auch gar nicht, ohne die Rückwärtskompatibilität zu
brechen.
C++ ist hier in einer Sackgasse.
MaWin O. schrieb:> Justin S. schrieb:>> Es muss doch völlig klar sein, dass die Menge der unbehobenen Bugs in>> "professioneller" Software proportional zur Menge des Source-Codes inkl.>> Libraries ist.>> Wieso sollte das völlig klar sein?> Das würde ja bedeuten, dass (1) alte Bugs nie behoben werden und (2)> neuer Code in etwa immer die gleiche Bugdichte hat.>> Bei (2) gehe ich mit, aber (1) ist doch Unsinn.
Dabei muss ich Justin recht geben. Je mehr Codezeilen umso mehr
potentielle Fehler können enthalten sein. Überlege mal wieviel
Programmzeilen man pro Tag so schreibt und wieviel Zeit für Testen und
Debuggen verplempert wird.
El Capitan schrieb:>> darüber mit RICHTIGEN Hochsprachen.> Welche nutzt Du für AVR/ESP/STM32?
Ich vermeide das böse Wort hier ganz bewusst, weil sonst die Trolle
wieder aus den Löchern geschossen kommen. :)
Ja, es gibt mindestens eine moderne Hochsprache ohne UB (und mit
expliziter UB-Freischaltung) für AVR/ESP/STM32.
Mehr sage ich dazu in diesem Thread nicht. Dazu gibt es schon einen in
"PC-Programmierung" (Ja, ist das falsche Forum. Der Thread hat sich halt
so entwickelt).
Beitrag "Rust - ist das hier um zu bleiben?"
Kernigham & Ritchie schrieb:> Dabei muss ich Justin recht geben. Je mehr Codezeilen umso mehr> potentielle Fehler können enthalten sein.
Das ist ja auch grundsätzlich richtig.
Aber Bugs werden auch behoben.
Also sinkt die Anzahl der Bugs in einem Programm, das (angenommen)
keinen neuen Code erhält stetig.
Das heißt, dass die Anzahl der Fehler eben nicht proportional zu den
Codezeilen ist, sondern eher umgekehrt-proportional zu deren Alter.
von MaWin O. (mawin_original)
>Kernigham & Ritchie schrieb:>> Da eine KI auch nur von jemanden programmiert wird>Eine "KI", also ein Machine Learning Algorithmus ist im Kern recht>einfach. Der Programmcode ist nicht das, wo die Leistung und die>Innovation drin steckt.
Das sehe ich ganz anders. Die Architekturen der Netze können sehr
komplex werden und erfordern ein langes Design mit menschlicher
Unterstützung.
Google ist dabei, auch das zu automatisieren:
https://ai.googleblog.com/2017/05/using-machine-learning-to-explore.html
Gerd schrieb:> Der Programmcode ist nicht das, wo die Leistung und die>>Innovation drin steckt.>> Das sehe ich ganz anders. Die Architekturen der Netze können sehr> komplex werden
Du hast mich falsch verstanden.
Ich sprach vom Programmcode. Nicht von der Netzarchitektur.
c-hater schrieb:> MaWin O. schrieb:>>> Einer der vielen Gründe, weshalb C/C++ endlich ersetzt werden sollten.>> Ganz genau. Sowas wie UB sollte es in einer Programmiersprache nicht> geben. Das zu fordernde Minimum für eine moderne Programmiersprache ist,> dass der Compiler sowas selber erkennt und eine Fehlermeldung> produziert. Alles darunter ist vollkommen indiskutabel.
Bei UB geht es um Situationen, die der Compiler nicht immer erkennen
kann, weil sie oft erst zur Laufzeit entstehen. Könnte der Compiler alle
Fehler immer zur Compilezeit erkennen, dann gäbe es auch in C kein UB.
Wenn ich den Benutzer zwei Zahlen eingeben lasse und die dann dividiere,
weiß der Compiler nicht, dass der Benutzer später mal als zweite Zahl
eine 0 eingeben wird. Da gibt es eben zwei Möglichkeiten, damit
umzugehen: Entweder der Compiler baut einen Laufzeitcheck ein, der vor
jeder Division prüft, ob der Divisor 0 ist und dann das Programm
terminiert oder eine Exception wirft oder was auch immer, oder man
akzeptiert eben, dass das UB ist. Bei C hat man sich aus
Effizienzgründen für zweiteres entschieden, wobei das dem Compiler nicht
verbietet, ersteres trotzdem zu tun, aber es zwingt ihn eben auch nicht
dazu.
Rolf M. schrieb:> Entweder der Compiler baut einen Laufzeitcheck ein, der vor> jeder Division prüft, ob der Divisor 0 ist und dann das Programm> terminiert oder eine Exception wirft oder was auch immer, oder man> akzeptiert eben, dass das UB ist.
Es gibt natürlich noch eine dritte Möglichkeit.
Wenn der Compiler beweisen kann, dass der Divisor nicht 0 werden kann,
braucht er auch keinen Check und es ist auch kein UB.
Dazu gibt es dann für nicht-triviale Fälle den Non-Zero-Integer, mit dem
der Programmierer dem Compiler beim Programmverständnis unter die Arme
greifen kann.
> Je mehr Codezeilen, je mehr Fehler
Das ist sogar schon durch wissenschaftliche Studien belegt.
> Bug-Beseitigung
Gerade in kommerzieller Software werden Bugs oft nicht beseitigt,
sondern "abgefangen", d.h. für den speziellen Fall wird zusätzlicher
Code hinzugefügt.
M.E. sind die riesigen Frameworks ein Teil des Problems, die können doch
gar nicht fehlerfrei sein. Dann haben wir noch eine Inflation an neuen
Features und schließlich noch die Kurzlebigkeit der Produkte.
Betriebssysteme "leben" heute nur noch 18 Monate, Programmiersprachen
wie JAVA gar nur noch 6 Monate. Von .NET gibt es schon x-Versionen,
wobei selbst für 2.x noch Updates kommen (immerhin). Sogar vor der
Hardware macht das nicht halt: auch die großen Hersteller können heute
eine Verfügbarkeit von einem Jahr nicht mehr garantieren.
Da können Systeme doch gar nicht mehr "ausreifen". Und weil man sich der
alten BWLer-Formel "nicht die Guten fressen die Schlechten, sondern die
Schnellen die langsamen" nicht entziehen kann, läßt sich das auch gar
nicht ändern.
Und wenn ich sehe, wie meine Kollegen Software entwickeln, dann wir mir
ohnehin schwummerig. Daß alles mit copy&paste zusammengeschustert wird,
geht ja noch. Aber teilweise werden Funktionen/Module/Bibliotheken
verwendet ohne den geringsten Versuch, deren Funktionsweise verstehen zu
wollen. Es reicht wenn mit den Testdaten das gewünschte Ergebnis erzielt
wird. Paßt schon.
@ Rolf
Bei dem Division 0 Bsp. gebe ich dir recht. Kann erst zur Laufzeit
überprüft werden und ist damit für den Compiler schwer zu handhaben. Ein
anderes negativ Bsp. für den Standard sind signed Überläufe auf UB
Status zu belassen. Das macht im Vergleich zu unsigned Überläufen keinen
Sinn. Wenn unsigned von 0 (min) auf max und umgekehrt springen kann,
dann sollte auch signed von min auf max und umgekehrt springen können.
Das erwartet die Programmiererlogik wenn man das unsigned
Überlaufverhalten kennt.
kleiner Admin schrieb:> Gerade in kommerzieller Software werden Bugs oft nicht beseitigt,> bla bla bla
Hast du auch Belege für deine ganzen Behauptungen?
In meiner Realität stimmt das alles nicht.
Software wird im Mittel immer komplexer und immer besser/fehlerfreier.
Das ist meine Wahrnehmung.
Und das lässt sich auch durch die zunehmende Anzahl und Qualität der
Entwicklungstools begründen (checker, linter, compiler, etc...).
Dass Hersteller keine Updates liefern ist doch auch kompletter Unsinn.
In Zukunft wird es trotzdem noch einige Verbesserungssprünge geben
(müssen).
Aber wenn ich heutige Software mit dem Schrott aus den 90ern vergleiche,
dann bin ich ganz froh im Jetzt zu leben. Auch wenn heutige Software bei
Weitem noch nicht perfekt und so fehlerfrei ist, wie ich mir das
wünschen würde.
MaWin O. schrieb:> Software wird im Mittel immer komplexer und immer besser/fehlerfreier.> Das ist meine Wahrnehmung.
Denke nur mal daran, wie oft man unter Windows 95 den Bluescreen bekam,
und wie oft heute. Zumindest in dieser Hinsicht wurde Windows erheblich
besser, trotz der 100 Fachen Größe.
Stefan F. schrieb:> Denke nur mal daran, wie oft man unter Windows 95 den Bluescreen bekam,> und wie oft heute.
Liegt das nur am Windows oder sind die Anwenderprogramme auch besser
geworden.
Windows wurde in der Hinsicht mit XP deutlich besser.
Dirk B. schrieb:> Liegt das nur am Windows oder sind die Anwenderprogramme auch besser> geworden.>> Windows wurde in der Hinsicht mit XP deutlich besser.
Modernere CPUs, OS/2 und seine Weiterentwicklung
Da ist die Verbesserung zu finden
In Hauptsache: Speicherschutz und preemptives Multitasking
Ich denke, dass man für das Thema undefined behavior nicht so ein großes
Fass aufmachen muss. Natürlich ist es an ein paar Ecken ärgerlich.
Meistens liegt man dann aber in Grenzbereichen, in denen man sich
eigentlich ohnehin zusätzliche Gedanken darüber machen müsste, was man
hier tut.
Der originale Fragesteller (der sich schon längst verabschiedet hat) ist
offensichtlich ein Anfänger der wild Datentypen gemischt hat und
scheinbar nicht die geringste Aufmerksamkeit in das Thema Wertbereich
gesteckt hat. Wenn sich ein Neuling ungeschickt mit der Kettensäge
anstellt, fließt nun mal Blut. In Java gibt es viel weniger UB - aber
dass an dieser Stelle wrap around definiert ist, würde dem fehlerhaften
Programm kein Stück weiterhelfen. Aus der Sicht des Regelkreises wäre
ein INT_MAX beim overflow vermutlich hilfreicher - aber das kostet
Performance wenn es nicht durch die Hardware unterstützt wird. Gibt es
vielleicht bei DSPs?
99% der Probleme lassen sich vermeiden, indem man warnings beachtet und
im Prinzip wie Fehler behandelt. Es gibt seltene Situationen, in denen
die warning nicht angemessen ist und auch nicht leicht behoben werden
kann. Dann kann man meiner Meinung nach auch mal eine Ausnahme machen
und die warning stehen lassen (natürlich gut Kommentiert damit andere
Entwickler nicht darüber stolpern). Ich könnte aber aus dem Stehgreif
noch nicht mal ein gutes Beispiel liefern, so selten sehe ich das
Problem.
Matthias T. schrieb:> Ich denke, dass man für das Thema undefined behavior nicht so ein großes> Fass aufmachen muss. Natürlich ist es an ein paar Ecken ärgerlich.
Es ist die Ursache für den Großteil der Sicherheitslücken, die ständig
gefunden werden.
Das halte ich für etwas mehr als nur "ärgerlich".
> In Java gibt es viel weniger UB
Bin kein Java-Experte, aber in Java gibt es doch gar kein UB, oder
nicht?
> dass an dieser Stelle wrap around definiert ist, würde dem fehlerhaften> Programm kein Stück weiterhelfen.
Doch, es hilft enorm.
Die Abwesenheit von UB transformiert nämlich ein "Der Compiler macht
einfach irgendwas" zu einem "Der Compiler macht das, was definiert ist".
Nach der Ausführung von UB ist der komplette restliche Programmablauf
undefiniert.
Und moderne C-Compiler nutzen diese Eigenschaft massiv aus, um den Code
zu optimieren.
> 99% der Probleme lassen sich vermeiden, indem man warnings beachtet und> im Prinzip wie Fehler behandelt.
Das stimmt nicht.
Die Bug-Statistiken sprechen eine andere Sprache.
In C können nur sehr wenige - praktisch keine - UBs zur Compilezeit
abgefangen werden.
Stefan F. schrieb:> Alles, was er nicht in Assembler programmieren kann, programmiert er gar> nicht. Also fast alles, offenbar.
DICH habe ich nicht gefragt!
El Capitan schrieb:> DICH habe ich nicht gefragt!
Ist mir doch egal. Ich habe keinen Respekt vor Leuten, die sich hinter
einer anonymen Fassade verbergen.
Matthias T. schrieb:> Ich denke, dass man für das Thema undefined behavior nicht so ein großes> Fass aufmachen muss. Natürlich ist es an ein paar Ecken ärgerlich.> Meistens liegt man dann aber in Grenzbereichen, in denen man sich> eigentlich ohnehin zusätzliche Gedanken darüber machen müsste, was man> hier tut.
Ja. Bei dem Beispiel der Division durch 0 muss man als Entwickler eben
seinen Code so schreiben, dass sie nicht vorkommen kann. Wenn die Zahl
also vom Benutzer kommt, baut man einen Check ein. Das UB kommt erst ins
Spiel, wenn der Entwickler das versäumt hat.
> 99% der Probleme lassen sich vermeiden, indem man warnings beachtet und> im Prinzip wie Fehler behandelt. Es gibt seltene Situationen, in denen> die warning nicht angemessen ist und auch nicht leicht behoben werden> kann. Dann kann man meiner Meinung nach auch mal eine Ausnahme machen> und die warning stehen lassen (natürlich gut Kommentiert damit andere> Entwickler nicht darüber stolpern).
Ich mache meinen Code komplett warnungsfrei, denn zwischen "unwichtigen"
Warnungen gehen die, die kritisch sind, gerne mal unter.
> Ich könnte aber aus dem Stehgreif noch nicht mal ein gutes Beispiel> liefern, so selten sehe ich das Problem.
Leider warnt gcc heute auch immer öfter bei stilistischen Dingen, die
für sich erst mal kein Problem sind, und da sind manchmal Sachen dabei,
wo ich anderer Meinung bin. Dann beiße ich eben in den sauren Apfel und
schreibe was unnütiges hin, damit der Compiler glücklich ist.
(Übrigens: Es heißt "Stegreif". Das Wort hat weder mit stehen, noch mit
greifen etwas zu tun).
MaWin O. schrieb:> Matthias T. schrieb:>> Ich denke, dass man für das Thema undefined behavior nicht so ein großes>> Fass aufmachen muss. Natürlich ist es an ein paar Ecken ärgerlich.>> Es ist die Ursache für den Großteil der Sicherheitslücken, die ständig> gefunden werden.
Da verwechselst du die Ursache mit der Wirkung. Die Ursache sind Fehler
im Programm, die Wirkung ist, dass dessen Verhalten dadurch undefiniert
wird. Und das kann im schlimmsten Fall ein Sicherheitsproblem sein.
>> In Java gibt es viel weniger UB>> Bin kein Java-Experte, aber in Java gibt es doch gar kein UB, oder> nicht?
Soweit ich weiß. Dafür sind dort dann eben die oben genannten
Laufzeitchecks enthalten und ein Fehler führt zu einer Exception, die
dann das Programm terminiert. Man kann sie natürlich auch fangen, aber
was soll man schon sinnvolles tun, wenn die geworfen wurde, weil
irgendwo im Programm ein Fehler ist, mit dem dessen Programmierer
natürlich nicht gerechnet hat?
>> 99% der Probleme lassen sich vermeiden, indem man warnings beachtet und>> im Prinzip wie Fehler behandelt.>> Das stimmt nicht.> Die Bug-Statistiken sprechen eine andere Sprache.
Zumindest bei den Dingen, die zur Compilezeit erkannt werden können,
dürfen natürlich vom Compiler auch Warnungen oder Fehlermeldungen
ausgegeben werden, denn auch das ist eine gültige Instanz von "undefined
behavior". Das ist dann aber keine Sache des Standards, sondern der
quality of implementation. Wie oben schon gesagt: Der Standard verbietet
es nicht, erzwingt es aber auch nicht.
> In C können nur sehr wenige - praktisch keine - UBs zur Compilezeit> abgefangen werden.
Naja, da gibt's schon ein paar, und da warnt ein gcc auch meistens.
Rolf M. schrieb:> Da verwechselst du die Ursache mit der Wirkung. Die Ursache sind Fehler> im Programm, die Wirkung ist, dass dessen Verhalten dadurch undefiniert> wird.
Nein, ich verwechsele nichts.
Eine Programmiersprache, die kein UB hat, kann kein undefiniertes
Verhalten hervorrufen. Egal, was der Programmierer sich
zusammenprogrammiert.
Und damit können diese Bugs nicht mehr derart eskalieren. Sie sind dann
maximal noch DoS-tauglich.
Rolf M. schrieb:> Ja. Bei der Division durch 0 muss man als Entwickler eben seinen Code so> schreiben, dass sie nicht vorkommen kann. Wenn die Zahl also vom> Benutzer kommt, baut man einen Check ein. Das UB kommt erst ins Spiel,> wenn der Entwickler das versäumt hat.
Ja. "man muss es nur richtig machen".
Ein Konzept, dass jetzt Jahrzehnte erprobt ist und nicht funktioniert.
Wir brauchen ein besseres Konzept, was diese Bugs sicher verhindert.
MaWin O. schrieb:> Rolf M. schrieb:>> Da verwechselst du die Ursache mit der Wirkung. Die Ursache sind Fehler>> im Programm, die Wirkung ist, dass dessen Verhalten dadurch undefiniert>> wird.>> Nein, ich verwechsele nichts.
Doch, schon.
> Eine Programmiersprache, die kein UB hat, kann kein undefiniertes> Verhalten hervorrufen. Egal, was der Programmierer sich> zusammenprogrammiert.
Genau. Dann ist dort die Wirkung eben eine andere, z.B. Terminierung des
Programms statt UB.
> Rolf M. schrieb:>> Ja. Bei der Division durch 0 muss man als Entwickler eben seinen Code so>> schreiben, dass sie nicht vorkommen kann. Wenn die Zahl also vom>> Benutzer kommt, baut man einen Check ein. Das UB kommt erst ins Spiel,>> wenn der Entwickler das versäumt hat.>> Ja. "man muss es nur richtig machen".> Ein Konzept, dass jetzt Jahrzehnte erprobt ist und nicht funktioniert.> Wir brauchen ein besseres Konzept, was diese Bugs sicher verhindert.
Es verhindert nicht die Bugs, sondern ändert wie schon gesagt nur ihre
Auswirkung. Damit will ich nicht sagen, dass das nicht von Vorteil wäre,
sondern nur, dass dann immer noch ein Bug im Programm ist.
MaWin O. schrieb:> Es gibt natürlich noch eine dritte Möglichkeit.>> Wenn der Compiler beweisen kann, dass der Divisor nicht 0 werden kann,> braucht er auch keinen Check und es ist auch kein UB.
Aber es geht ja gerade um den Fall, in dem der Compiler das nicht
beweisen kann. Damit muss er irgendwie umgehen.
Rolf M. schrieb:> Doch, schon.
Ach komm. Das kann doch nicht dein Ernst sein.
Ich weiß doch wohl selbst besser als du, was ich meine.
> Es verhindert nicht die Bugs, sondern ändert wie schon gesagt nur ihre> Auswirkung. Damit will ich nicht sagen, dass das nicht von Vorteil wäre,> sondern nur, dass dann immer noch ein Bug im Programm ist.
Nein, das ist so allgemein gesagt nicht richtig.
In vernünftigen modernen Sprachen sind sehr viele Dinge, die in C UB
sind, einfach Compilerfehler. Es verhindert also die Bugs.
Nur bei den wenigen Dingen die zur Laufzeit geprüft werden, sind die
Bugs weiterhin formell im Programm. Aber massiv entschärft.
> Aber es geht ja gerade um den Fall, in dem der Compiler das nicht> beweisen kann. Damit muss er irgendwie umgehen.
Das heißt aber noch lange nicht, dass er bei jeder Division die Prüfung
machen muss. Und das wurde ja hier behauptet. Es ist falsch.
MaWin O. schrieb:> Matthias T. schrieb:>> Ich denke, dass man für das Thema undefined behavior nicht so ein großes>> Fass aufmachen muss. Natürlich ist es an ein paar Ecken ärgerlich.>> Es ist die Ursache für den Großteil der Sicherheitslücken, die ständig> gefunden werden.
Ich habe keine belastbaren Statistiken zur Hand. Aber ich denke, dass
die manuelle Speicherverwaltung (Array Überlauf, use after free etc.) in
der Praxis ein viel größeres Problem darstellt.
>> In Java gibt es viel weniger UB>> Bin kein Java-Experte, aber in Java gibt es doch gar kein UB, oder> nicht?
Im Zusammenhang mit multi threading und bei einzelnen Libs gibt UB auch
in Java. Und zum Teil wird es auch durch Haarspalterei "getarnt" - dann
heißt es eben "implementation defined behavior". Für den Anwender läuft
es auf das gleiche hinaus, das Programmverhalten kann sich von Umgebung
zu Umgebung deutlich ändern. Ist aber in Java recht selten.
>>> dass an dieser Stelle wrap around definiert ist, würde dem fehlerhaften>> Programm kein Stück weiterhelfen.>> Doch, es hilft enorm.> Die Abwesenheit von UB transformiert nämlich ein "Der Compiler macht> einfach irgendwas" zu einem "Der Compiler macht das, was definiert ist".> Nach der Ausführung von UB ist der komplette restliche Programmablauf> undefiniert.
Der Standard sagt (frei formuliert), dass der Compiler bei UB auch rosa
Einhörner produzieren darf. Das heißt aber nicht, dass der Compiler das
auch tut. Die meisten Compiler versuchten das zu tun, was am
vernünftigsten erscheint (dem Compilerbauer, das muss sich nicht mit der
Erwartungshaltung des Entwicklers decken). Und insbesondere kenne ich
keinen Compiler, der mal so und mal so arbeitet. Beim Integer Überlauf
in Berechnungen machen alle einen wrap around (wie bei Java definiert -
also kein Unterschied im Verhalten).
Ein Laie mag es vielleicht überraschend finden, wenn der Compiler eine
if-Entscheidung mit einem unsigned int gegen eine negative Zahl einfach
wegoptimiert. Aber es ist nun mal ein bug im Programm, nicht im
Compiler. Hier sind wir wieder beim Thema "warnings ernst nehmen!".
> In C können nur sehr wenige - praktisch keine - UBs zur Compilezeit> abgefangen werden.
Ich bin auch kein großer Fan von C. Aber man muss eben auch
Zugeständnisse an die Entstehungsgeschichte machen und das Thema
Kompatibilität beachten. Jedes hinreichend alte Produkt schleppt eine
Reihe von Altlasten mit sich rum. Und wie bereits jemand anderes
geschrieben hat - wie willst Du Deinen AVR (synonym für kleine
Microcontroller) anders programmieren als mit C oder C++? Man kann Rust
nehmen (wenn man es denn mag). Ich habe auch über ADA (Sparc)
nachgedacht. Aber beide Umgebungen leiden dann wieder unter
eingeschränkten Libraries. Und ich mag nicht ständig das Rad neu
erfinden. Für mich ist es aber auch nur Hobby, beruflich arbeite ich
nicht mit Microcontrollern.
Matthias T. schrieb:> Ich habe keine belastbaren Statistiken zur Hand. Aber ich denke, dass> die manuelle Speicherverwaltung (Array Überlauf, use after free etc.) in> der Praxis ein viel größeres Problem darstellt.
Das ist alles UB.
UB zu verhindern, verhindert also auch diese Dinge.
Matthias T. schrieb:> Im Zusammenhang mit multi threading und bei einzelnen Libs gibt UB auch> in Java. Und zum Teil wird es auch durch Haarspalterei "getarnt" - dann> heißt es eben "implementation defined behavior". Für den Anwender läuft> es auf das gleiche hinaus, das Programmverhalten kann sich von Umgebung> zu Umgebung deutlich ändern.
Was nicht heißt, dass es UB ist.
> Der Standard sagt (frei formuliert), dass der Compiler bei UB auch rosa> Einhörner produzieren darf. Das heißt aber nicht, dass der Compiler das> auch tut.
Doch, das heißt es. Sehr oft. Die Bugtracker sind voll mit solchen
Reports, die als invalid geschlossen werden.
> Und insbesondere kenne ich> keinen Compiler, der mal so und mal so arbeitet.
Das habe ich nicht behauptet.
> Beim Integer Überlauf> in Berechnungen machen alle einen wrap around
Das bei gängigen C-Compilern definitiv nicht so. Die nutzen
signed-overflow-UB aktiv aus um zu optimieren.
> Jedes hinreichend alte Produkt schleppt eine> Reihe von Altlasten mit sich rum.
Ja. Das ist aber kein Grund es nicht besser zu machen.
> wie willst Du Deinen AVR (synonym für kleine> Microcontroller) anders programmieren als mit C oder C++?> Man kann Rust> nehmen (wenn man es denn mag).
Zum Beispiel.
> Für mich ist es aber auch nur Hobby
Ja gut.
Für mich nicht.
Rolf M. schrieb:> Leider warnt gcc heute auch immer öfter bei stilistischen Dingen, die> für sich erst mal kein Problem sind, und da sind manchmal Sachen dabei,> wo ich anderer Meinung bin. Dann beiße ich eben in den sauren Apfel und> schreibe was unnütiges hin, damit der Compiler glücklich ist.
Mittlerweile unterdrücke ich Warnungen sogar.
Hier die am meisten nerven:
-pedantic (für mich nicht relevant, da nur GCC in Verwendung)
-Wno-volatile (denn ich weiß, dass |= nicht atomar ist)
EAF schrieb:> -Wno-volatile (denn ich weiß, dass |= nicht atomar ist)
Bei der Warnung geht es nicht darum, ob der Operator atomar ist, sondern
darum, wie oft die side-effects ausgelöst werden sollen. Denn das ist
schlicht nicht vollständig definiert.
MaWin O. schrieb:>> Beim Integer Überlauf>> in Berechnungen machen alle einen wrap around>> Das bei gängigen C-Compilern definitiv nicht so. Die nutzen> signed-overflow-UB aktiv aus um zu optimieren.
Es ist mir nicht klar, was Du damit meinst? Der overflow in Berechnungen
kann im Allgemeinen zur Compile-Zeit noch nicht erkannt werden. Die
Hardware macht ein wrap around, das Overflow Flag wird von C genauso wie
von Java einfach ignoriert. Und von Rust - wenn man nicht im debug mode
ist - scheinbar genauso:
"When the programmer has enabled debug_assert! assertions (for example,
by enabling a non-optimized build), implementations must insert dynamic
checks that panic on overflow. Other kinds of builds may result in
panics or silently wrapped values on overflow, at the implementation's
discretion."
>>> Jedes hinreichend alte Produkt schleppt eine>> Reihe von Altlasten mit sich rum.>> Ja. Das ist aber kein Grund es nicht besser zu machen.
Das ist manchmal nicht einfach wenn man die Anwender mitnehmen will.
Sieht Phyton 2 nach 3. Selbst kleine Änderungen/ Verbesserungen können
dazu führen, dass viele Anwender nicht umsteigen können oder wollen.
Mir gefällt in Java auch viel besser, dass es kaum Probleme mit der
Speicherverwaltung gibt. Aber es kommt halt auch mit einem Preis. Ja
nach Situation kann es akzeptabel sein oder nicht.
MaWin O. schrieb:> Deshalb braucht ein C/C++ Ersatz immer die Möglichkeit die UB-Freiheit> stellenweise, dort wo es notwendig ist, vom Programmierer attestieren zu> lassen. (Also das, was der Programmierer in C/C++ für das gesamte> Programm tun muss)
Das ist eine ziemlich treffende Beschreibung, wie Ada die Problematik
behandelt.
Matthias T. schrieb:> Es ist mir nicht klar, was Du damit meinst? Der overflow in Berechnungen> kann im Allgemeinen zur Compile-Zeit noch nicht erkannt werden.
Es wird vom Compiler angenommen, dass kein overflow vorkommt.
Das führt dann zum Beispiel dazu, dass Code eliminiert wird, der unter
dieser Annahme niemals ausgeführt werden könnte.
Wenn es dann zur Laufzeit aber doch zu einem overflow kommt, dann
fehlt der behandelnde Code.
Und das ist nur eine von vielen möglichen Optimierungen.
> Das ist manchmal nicht einfach
Das hat ja auch niemand gesagt.
Aber die Probleme, die UB bereitet, sind aber auch massiv.
Da kann man sich schon einmal eine nicht-einfache Lösung anschauen.
> Mir gefällt in Java auch viel besser, dass es kaum Probleme mit der> Speicherverwaltung gibt. Aber es kommt halt auch mit einem Preis.
In Java schon.
In anderen sicheren Sprachen aber nicht.
Zum Beispiel use-after-free und Objektlebenszeiten können in anderen
Sprachen zur Compilezeit geprüft werden.
Markus F. schrieb:> Das ist eine ziemlich treffende Beschreibung, wie Ada die Problematik> behandelt.
Ja. Und viele andere Sprachen.
Es sollen ja nur die schlechten Konzepte über Bord geworfen werden. Auch
in C gibt es ja gute Dinge. Die sollen ja weiterleben.
Matthias T. schrieb:> MaWin O. schrieb:>>> Beim Integer Überlauf>>> in Berechnungen machen alle einen wrap around>>>> Das bei gängigen C-Compilern definitiv nicht so. Die nutzen>> signed-overflow-UB aktiv aus um zu optimieren.>> Es ist mir nicht klar, was Du damit meinst? Der overflow in Berechnungen> kann im Allgemeinen zur Compile-Zeit noch nicht erkannt werden. Die> Hardware macht ein wrap around, das Overflow Flag wird von C genauso wie> von Java einfach ignoriert.
Der Compiler darf alles machen, was er will unter der Annahme, dass ein
Overflow nicht stattfindet. Da kann ein Wert auch mal größer werden als
es der Typ eigentlich zulässt, z.B. weil ein ARM-Prozessor nicht in 8
oder 16 Bit rechnen kann, sondern nur in 32 Bit. Der Compiler müsste
dann nach der Berechnung Zwischenwerte entweder maskieren, um den
Wertebereich zu begrenzen oder den Wert in den Speicher schreiben und
zurück lesen. Wenn er aber davon ausgehen darf, dass der Wertebereich
nie verlassen wird, kann er diese zusätzliche Aktion weglassen. Das ist
nur eine mögliche Optimierung, die zu einem anderen als dem von dir
erwarteten Verhalten führt. Da gibt es noch ganz andere Sachen.
> Mir gefällt in Java auch viel besser, dass es kaum Probleme mit der> Speicherverwaltung gibt.
Dafür dann mit der Verwaltung anderer Ressourcen, weil die von der
Speicherverwaltung abgekoppelt ist.
MaWin O. schrieb:> Rolf M. schrieb:>> Doch, schon.>> Ach komm. Das kann doch nicht dein Ernst sein.> Ich weiß doch wohl selbst besser als du, was ich meine.
So ist das eben. Wenn man etwas verwechselt, weiß man nicht immer, dass
man das gerade tut.
>> Es verhindert nicht die Bugs, sondern ändert wie schon gesagt nur ihre>> Auswirkung. Damit will ich nicht sagen, dass das nicht von Vorteil wäre,>> sondern nur, dass dann immer noch ein Bug im Programm ist.>> Nein, das ist so allgemein gesagt nicht richtig.> In vernünftigen modernen Sprachen sind sehr viele Dinge, die in C UB> sind, einfach Compilerfehler. Es verhindert also die Bugs.>> Nur bei den wenigen Dingen die zur Laufzeit geprüft werden, sind die> Bugs weiterhin formell im Programm. Aber massiv entschärft.
Das klingt, als sei UB maßgeblich etwas, das zur Compilezeit auftritt,
was so nicht stimmt. Außerdem ist es dem Compiler wie gesagt nicht
verboten, solche Fehler dem Programmierer mitzuteilen.
>> Aber es geht ja gerade um den Fall, in dem der Compiler das nicht>> beweisen kann. Damit muss er irgendwie umgehen.>> Das heißt aber noch lange nicht, dass er bei jeder Division die Prüfung> machen muss. Und das wurde ja hier behauptet. Es ist falsch.
Er muss halt erkennen, bei welchen Divisionen die Prüfung nötig ist, und
das ist oft alles andere als trivial. Aber ja, manchmal geht das.
warning: compound assignment with 'volatile'-qualified left operand is
deprecated [-Wvolatile]
Warum ist eigentlich auch egal, die Meldungen (diese spezielle) nerven
dennoch.
Zudem ist, zumindest bei den AVR, recht klar was da passiert.
Rolf M. schrieb:> Dann beiße ich eben in den sauren Apfel und> schreibe was unnütiges hin, damit der Compiler glücklich ist.
Das ist irgendwie nicht wirklich die ultimative Lösung, da da solche
read-modify-write Dinger/Operatoren in Massen bei den AVRs eingesetzt
wurden und werden.
Unmengen fertiger Anwendungen und Librarys müssen geändert werden.
Rolf M. schrieb:> Er muss halt erkennen, bei welchen Divisionen die Prüfung nötig ist, und> das ist oft alles andere als trivial.
Ich habe bereits geschrieben, wie man diese Entscheidung verbessern
kann.
Zum Rest deines Beitrages sage ich nichts. Das ist mir zu dumm.
EAF schrieb:> Warum ist eigentlich auch egal, die Meldungen (diese spezielle) nerven> dennoch.
Naja. Du hast halt den falschen Grund genannt und ich habe es
korrigiert.
Nicht mehr und nicht weniger.
Dass die AVR-Libc dieses veraltete Konstrukt nutzt, ist natürlich
schlecht. Keine Frage. Das legitimiert das Abschalten dieser Warnung
natürlich, bis die AVR-Libc gefixt ist.
> Zudem ist, zumindest bei den AVR, recht klar was da passiert.
Ja. Das ist implementation defined.
MaWin O. schrieb:> Rolf M. schrieb:>> Er muss halt erkennen, bei welchen Divisionen die Prüfung nötig ist, und>> das ist oft alles andere als trivial.>> Ich habe bereits geschrieben, wie man diese Entscheidung verbessern> kann.
Und ich habe bereits mehrfach geschrieben, dass die Sprache dem Compiler
nirgends verbietet, das zu tun.
> Zum Rest deines Beitrages sage ich nichts. Das ist mir zu dumm.
Wie du meinst…
MaWin O. schrieb:> Matthias T. schrieb:>> Es ist mir nicht klar, was Du damit meinst? Der overflow in Berechnungen>> kann im Allgemeinen zur Compile-Zeit noch nicht erkannt werden.>> Es wird vom Compiler angenommen, dass kein overflow vorkommt.> Das führt dann zum Beispiel dazu, dass Code eliminiert wird, der unter> dieser Annahme niemals ausgeführt werden könnte.>> Wenn es dann zur Laufzeit aber doch zu einem overflow kommt, dann> fehlt der behandelnde Code.
Welche Programmiersprache erzeugt extra Code für die overflow Behandlung
in Berechungen? Ich meine nicht das Thema "Vergleiche unsigned mit
negativen Wert", sondern ganz normale Berechnungen. Ich denke, dass es
nicht viele Beispiele gibt. Und was machen die dann - außer einer
Exception werfen (was natürlich schon mal eine Hilfe wäre)?
Ich glaube auch, dass das Thema bei 8 Bit und 16 Bit Prozessoren
durchaus problematisch war. Bei 32 Bit und noch viel weniger bei 64 Bit
Prozessoren wird es wohl nicht so ein großes Problem sein.
>> In Java schon.> In anderen sicheren Sprachen aber nicht.>> Zum Beispiel use-after-free und Objektlebenszeiten können in anderen> Sprachen zur Compilezeit geprüft werden.
Nirgends wo kommt es ohne Aufpreis. In modernen C++ (Libs) wird es über
escape analysis und/ oder reference counting gemacht, das erzeugt aber
auch overhead. Und reference counting und multi tasking vertragen sich
nicht besonders gut. In Rust erkauft man es sich mit einem etwas
schrägen handling, an das man sich aber vermutlich gewöhnen kann. Die
vollständige Ermittlung von Objektlebenszeiten nur zur Compilezeit wäre
mir neu - welche Sprache macht das?
Rolf M. schrieb:> Und ich habe bereits mehrfach geschrieben, dass die Sprache dem Compiler> nirgends verbietet, das zu tun.
Ja. Was niemand jemals bestritten hat.
Es ist in C aber sehr sehr schwierig solche Optimierungen zu machen,
weil das Typsystem so schlecht ist.
Es gibt zum Beispiel (nur eines von vielen) keinerlei explizite
Möglichkeiten die Wertebereiche von Skalaren so einzuschränken, dass es
dem Compiler bessere Optimierungen ermöglicht.
Dass der C-Standard "X, Y, Z nicht verbietet" und "dem Compiler die
Möglichkeiten lässt dies und jenes zu tun", das ist ja gerade der größte
Teil des Problems.
Ich weiß, dass langjährige C-Programmierer sich das sehr schwer
vorstellen können, dass Dinge die in C Laufzeit kosten, in vernünftigen
Sprachen kostenlos und sicherer sein können.
Matthias T. schrieb:> Welche Programmiersprache erzeugt extra Code für die overflow Behandlung> in Berechungen?
Das hat niemand gesagt.
Matthias T. schrieb:> Nirgends wo kommt es ohne Aufpreis.
Eben doch.
> Die> vollständige Ermittlung von Objektlebenszeiten nur zur Compilezeit wäre> mir neu - welche Sprache macht das?
Ich schrieb nichts von vollständig.
Aber es reicht in der Regel aus, wenn es im weit überwiegenden Teil der
Fälle so ist.
Und wenn dir das in den restlichen wenigen Fällen immer noch nicht
ausreicht, dann darfst du gerne für diese Fälle unsichere Konstrukte
nutzen. Wäre mir jetzt aber noch nicht untergekommen.
MaWin O. schrieb:> Matthias T. schrieb:>> Welche Programmiersprache erzeugt extra Code für die overflow Behandlung>> in Berechungen?>> Das hat niemand gesagt.
Also reduziert es sich doch wieder auf die if-Thematik. Das ist so eine
Stelle an der die warning unbedingt wie ein Fehler behandelt werden
sollte. Ich gehe davon aus, dass es nur eine warning ist, weil aus
historischen Gründen viel "cleverer" oder auch schlampiger Code
existiert und hier die Kompatibilität schwerer wiegt. Von mir aus könnte
es ein normaler bug sein, der die Übersetzung abbricht.
>> Matthias T. schrieb:>> Nirgends wo kommt es ohne Aufpreis.>> Eben doch.>>> Die>> vollständige Ermittlung von Objektlebenszeiten nur zur Compilezeit wäre>> mir neu - welche Sprache macht das?>> Ich schrieb nichts von vollständig.
Das hast Du geschrieben: "Zum Beispiel use-after-free und
Objektlebenszeiten können in anderen Sprachen zur Compilezeit geprüft
werden."
Da steht nicht das Wort vollständig. Aber eine Speicherverwaltung, die
nur manchmal funktioniert und manchmal nicht, ist nicht besonders
praktisch.
Matthias T. schrieb:> Aber eine Speicherverwaltung, die> nur manchmal funktioniert und manchmal nicht, ist nicht besonders> praktisch.
Tut mir leid. Du drehst mir jetzt zum wiederholten Male die Worte im
Munde herum.
Trolle unterstütze ich nicht weiter.
MaWin O. schrieb:> Matthias T. schrieb:>> Aber eine Speicherverwaltung, die>> nur manchmal funktioniert und manchmal nicht, ist nicht besonders>> praktisch.>> Tut mir leid. Du drehst mir jetzt zum wiederholten Male die Worte im> Munde herum.> Trolle unterstütze ich nicht weiter.
Wenn ich nicht verstehe oder errate welche Programmiersprache Du meinst,
dann schreib es doch einfach. Eine Speicherverwaltung muss alle
Objektinstanzen verwalten die ihr unterliegen. Das ist genau das Problem
der manuellen Speicherverwaltung bei C und dem manchmal mangelhaften
Verwalter "Mensch".
Matthias T. schrieb:> Welche Programmiersprache erzeugt extra Code für die overflow Behandlung> in Berechungen? Ich meine nicht das Thema "Vergleiche unsigned mit> negativen Wert", sondern ganz normale Berechnungen. Ich denke, dass es> nicht viele Beispiele gibt. Und was machen die dann - außer einer> Exception werfen (was natürlich schon mal eine Hilfe wäre)?
Standard-Ada würde eine Exception werfen (so man das will).
GNAT (Gnu Ada) in Verbindung mit SPARK ("reduziertes" Ada, das
vollständige Verifikation erlaubt) würde über hinzuzufügende Contracts
sicherstellen, dass der Überlauf gar nicht stattfinden kann. Ist das
Programm einmal so verifiziert, kann man es ohne Runtime-Checks
compilieren und erreicht (meist
https://en.wikipedia.org/wiki/SPARK_(programming_language)) dieselbe
Performance wie C/C++.
Matthias T. schrieb:> Der Standard sagt (frei formuliert), dass der Compiler bei UB auch rosa> Einhörner produzieren darf. Das heißt aber nicht, dass der Compiler das> auch tut. Die meisten Compiler versuchten das zu tun, was am> vernünftigsten erscheint (dem Compilerbauer, das muss sich nicht mit der> Erwartungshaltung des Entwicklers decken). Und insbesondere kenne ich> keinen Compiler, der mal so und mal so arbeitet.
Doch, z.B. der GCC. Das folgende Programm verhält sich je nach
Optimierungsstufe (-O0 oder -O1) unterschiedlich, was aber wegen des UB
völlig in Ordnung ist:
Yalu X. schrieb:> Doch, z.B. der GCC. Das folgende Programm verhält sich je nach> Optimierungsstufe (-O0 oder -O1) unterschiedlich, was aber wegen des UB> völlig in Ordnung ist...
Natürlich ist das GCC-Verhalten hier standardkonform, trotzdem finde ich
das Beispiel einigermassen fragwürdig. Die Warnung
kommt nur bei eingeschalteter Optimierung (trotz -Wall). Obwohl der
Compiler hier alles an der Hand hat, auch ohne Optimierung leicht UB
festzustellen. Schmeckt mir ein bisschen nach Compilerbauer-Häme...
Markus F. schrieb:> Schmeckt mir ein bisschen nach Compilerbauer-Häme...
Die Warnung könnte vielleicht trotzdem kommen, allerdings vermute ich,
daß das im Compiler tatsächlich erst im loop-Optimierungsschritt
auffällt.
Ohne Optimierung wirds halt einfach wie gewünscht funktionieren. Da
nutzt der Compilers sein Wahlrecht, bei UB einfach was für ihn passendes
zu machen, und lässt den signed integer klaglos überlaufen.
Oliver
Oliver S. schrieb:> Die Warnung könnte vielleicht trotzdem kommen, allerdings vermute ich,> daß das im Compiler tatsächlich erst im loop-Optimierungsschritt> auffällt.
GNU Ada bringt - unabhängig von der Optimierungsstufe (und ohne
irgendwelche extra Warnings einzuschalten):
1
5:20: warning: loop range is null, loop will not execute [enabled by default]
Rolf M. schrieb:> Bei C hat man sich aus Effizienzgründen für zweiteres entschieden,> wobei das dem Compiler nicht verbietet, ersteres trotzdem zu tun,> aber es zwingt ihn eben auch nicht dazu.
Bei GCC zum Beispiel so:
1
int volatile b = 0;
2
3
int main (void)
4
{
5
return 1 / b;
6
}
Übersetzt ohne Diagnostics und gibt beim Ausführen:
1
Floating point exception (core dumped)
zusätzlich generiert mit -fsanitize=undefined ergibt wie erwartet
ebenfalls keine Diagnostic. Ausführen:
1
main.c:5:14: runtime error: division by zero
2
Floating point exception (core dumped)
Die Frage ist dann, ob es möglich ist, damit zu entwickeln, weil
1) Man braucht genügend Resourcen (Speicher und Zeit) um die
Instrumentierungen machen zu können. Aufm PC kein Problem, auf einem
sehr beschränkten Embedded System aber schon. *)
2) Jemandem muss es wichtig genug gewesen sein, das für die
Zielarchitektur zu unterstützen. Für avr-gcc zum Beispiel gibt's keine
entsprechenden Sanitizer (libubsan.a etc). Hindernis ist wohl, fehlende
C++ und Atomic Unterstützung.
*) Prinzipiell wäre es möglich, entsprechende Features in einen
Simulator auszulagern, aber gerade auf Echtzeitsystemen bringt
Simulation ihre eigenen Probleme, die Simulation u.U. obsolet machen.
Außerdem hätte man eine wenig wünschenserte Kopplung zwischen Simulator
einerseits und Compiler(n) und Target-Libs andererseits.
> peda schrieb ..>Ich hab die Erfahrung gemacht, wenn nichts dagegen spricht, macht man
eine Regelung vorzugsweise in float. Besonders alle Arten von
Temperaturregelungen sind aus CPU-Sicht schnarch langsam.
Sicher nicht. Was soll das denn bringen ? Exponenten..
Ich rechne Regelungen, auch Temperaturregelungen mit 32bit.
Worauf regle ich ? Mit welchem Kooridinatensystem ? Auf ADC Werte, oder
2^N fache
Der Sollwert ist der ADC Wert des Sensors. zB von einem 24bit Wandler.
Oder wenn's nur ein 10bit Wander ist, auf des 16 fache. Auf Temperaturen
umgerechnet wird nur bei Bedarf, wenn der Benutzer die auch abfragt.
Sonst macht die keinen Sinn.
Das Stellglied wird mit einem gerechneten 32bit Wert shift N
angesteuert.
Da auf ADC Fehler = Null geregelt wird, wird der optimalerweise beliebig
gut erreicht und gehalten.
Ah, ja. Overflows. Um eine Addition vor Overflow zu schuetzen arbeitet
man mit bounded Variablen. Der Overflow wird auf das Maximum resp
Minimum gesetzt
Seien die Variable A und B
if ($7FFFFFFF-A) <B) { A+B => $7FFFFFFF) // A positiv overflow
if ($80000000+A) >B) { A+B => $80000000) // A negativ overflow
Waehrend des Entwicklungsprozesses sollte man das natuerlich testen und
vermeiden. Was auch immer die Ursachen sind. Solange nur das Stellglied
an den Anschlag geht, runterskalieren.
Purzel H. schrieb:> if ($7FFFFFFF-A) <B) { A+B => $7FFFFFFF) // A positiv overflow
Wenn A und B unsigned sind, schön. Wenn es aber signed integers sind,
dann wird dich damit der Blitz des UB voll treffen, mit für dich
unerwarteten Ergebnissen ;)
Oliver
Stefan F. schrieb:> Wen man damit ein einzelnes Bit in SFR <= 0x1F setzt, macht er eine> atomare SBI Operation:
Was willst du mir damit sagen?
Dass das so mit allen AVR und allen Registern klappt?
Das wäre ein Irrtum!
>> Wenn man damit ein einzelnes Bit in SFR <= 0x1F setzt, macht er eine>> atomare SBI OperationEAF schrieb:> Was willst du mir damit sagen?> Dass das so mit allen AVR und allen Registern klappt?> Das wäre ein Irrtum!
Damit will ich genau das sagen, was ich geschrieben habe. Du darfst
gerne davon abweichende Aussagen erfinden und dich darüber aufregen,
solange du anerkennst, dass es deine Phantasien sind.
Stefan F. schrieb:> Damit will ich genau das sagen, was ich geschrieben habe.
Super: Hauptsache was gesagt!
Gegen die Warnung hilft allerdings auch dein Sagen nichts.
Schlicht irrelevant.
⚡Guido⚡ schrieb:> El Capitan schrieb:>> Welche nutzt Du für AVR/ESP/STM32?>> Pascal:-)> Kein Scherz
Das sehe ich absolut nicht als Scherz.
Von Pascal kann sich C sicher noch "ein paar Scheiben abschneiden".
Welchen Pascal Compiler nutzt Du konkret?
S.E. schrieb:> Von Pascal kann sich C sicher noch "ein paar Scheiben abschneiden".
Das wird nicht passieren, weil C viel älter ist und Kompatibilität zu
diesem alten Standard dessen heilige Kuh ist. Wenn die Entwicklung von C
diesbezüglich anders wären, dann würde es C wahrscheinlich nicht mehr
geben.
Das "anders-sein" überlassen die C Entwickler mit voller Absicht den
anderen Programmiersprachen. C wird sich nicht ändern.
Mikroe Pascal
Du könntest auch gleich konsequent auf FreePascal gehen, damit habe ich
aber noch nichts am uC gemacht, und da es kein Kommerzielles Produkt
ist, ist sicher auch mehr Frickelei dabei, mit Mikroe bis Du da besser
bedient und der Wechsel von AVR zu ARm ist damit easy möglich, ohne irre
viel am Code ändern zu müssen