Forum: Mikrocontroller und Digitale Elektronik Überlauf in AVR mit C


von Pavel (pavelpalavel)


Lesenswert?

Hallo zusammen,

ich möchte einen P-Regler programmieren und bin gerade zu dumm dafür. 
Hier mein Code:
1
int32_t P_Teil;
2
int32_t e;     // Regeldifferenz
3
uint8_t P;     // 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
    else if ((P*e) > 65535) P_Teil = 65535;
12
    else if ((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

von Martin (Gast)


Lesenswert?

uint <-> int ?

von EAF (Gast)


Lesenswert?

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.

von Pavel (pavelpalavel)


Lesenswert?

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

von A. S. (Gast)


Lesenswert?

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?

von Martin (Gast)


Lesenswert?

Dann verwende mal einen Debuger bzw. mache ein paar Debug-prints.

von A. S. (Gast)


Lesenswert?

Ups, jetzt seh ich es: deine IFS gelten nur für < und >, nicht für== 
oder >=

von Peter D. (peda)


Lesenswert?

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.

von A. S. (Gast)


Lesenswert?

Rechne PTeil einfach aus und mach das clipping nachher direkt mit PTeil

von Dirk B. (dirkb2)


Lesenswert?

Welchem Wertebereich hat e?

Davon hängt das Vorzeichen ab.
Evtl kannst du dies als Unterscheidung nehmen
1
P_Teil = P * e; // muss immer berechnet werden.
2
if (((e<0) && (P_Teil > 0)) || (P_Teil < -65535)) P_Teil = -65535;
3
if (((e>0) && (P_Teil < 0)) || (P_Teil >  65535)) P_Teil =  65535;

von Dirk B. (dirkb2)


Lesenswert?

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.

von Veit D. (devil-elec)


Lesenswert?

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 ...

von Rolf M. (rmagnus)


Lesenswert?

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 ;-)

von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

Pavel schrieb:
>
1
> int32_t P_Teil;
2
> int32_t e;     // Regeldifferenz
3
> uint8_t P;     // Verstärkung
4
> P_Teil = P * e; und ((P*e) > 65535)
5
>

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...

von Oliver S. (oliverso)


Lesenswert?

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

von Werner (Gast)


Lesenswert?

Debug das ganze doch mal mit Beispielwerten,
dann wirst du den Fehler vermutlich selbst finden,
wenn nicht hilft es anderen den Fehler zu finden

von kleiner Admin (Gast)


Lesenswert?

Fehlen in Zeile 7 nicht Klammern?
1
if (((P*e) < 65535) && ((P*e) > -65535))

Ich würde das Ganze aber in zwei if-Abfragen umformulieren, das ist dann 
auch übersichtlicher und besser zu warten.
1
int32_t P_Teil;
2
int32_t e;     // Regeldifferenz
3
uint8_t P;     // Verstärkung
4
5
while(1){
6
    e = T_soll - T_ist;
7
    P_Teil = P * e;
8
    if (P_Teil > 65535 ) { P_Teil = 65535; }
9
    if (P_Teil < -65535 ) { P_Teil = -65535; }
10
}

von Klaus (feelfree)


Lesenswert?

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.

: Bearbeitet durch User
von Matthias Thiele (Gast)


Lesenswert?

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...

von Oliver S. (oliverso)


Lesenswert?

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

von Rolf M. (rmagnus)


Lesenswert?

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".

von EAF (Gast)


Lesenswert?

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

von Oliver S. (oliverso)


Lesenswert?

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

von Rolf M. (rmagnus)


Lesenswert?

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.

: Bearbeitet durch User
von Matthias T. (matthiasthiele)


Lesenswert?

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.

von EAF (Gast)


Lesenswert?

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...

von Matthias T. (matthiasthiele)


Lesenswert?

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;

von Stefan F. (Gast)


Lesenswert?

Matthias T. schrieb:
> int x = -655365;

Ja klar, wenn man da eine Ziffer zu viel hin schreibt :-)

Die Fehlermeldung kommt aber auch bei -65535

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

-65535 ist ja auch long und passt nicht in int.

: Bearbeitet durch User
von EAF (Gast)


Lesenswert?

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.

von Matthias T. (matthiasthiele)


Lesenswert?

Autsch - dabei habe ich gar nicht so dicke Finger.

von Matthias T. (matthiasthiele)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von EAF (Gast)


Lesenswert?

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.

von Dirk B. (dirkb2)


Lesenswert?

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

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Man kann sich den Typ eines Literals oder allgemeiner eines Ausdrucks 
auch "anzeigen" lassen:
1
void (*f1) (__typeof__(65535));
2
void (*f2) (__typeof__(0.0));
3
4
void func (void)
5
{
6
    f1 = f2;
7
}
Übersetzt mit -W:
1
warning: assignment to 'void (*)(long int)' from incompatible pointer type 'void (*)(double)' [-Wincompatible-pointer-types]
2
     f1 = f2;
3
        ^
Hier ist 65535 also "long int".

von EAF (Gast)


Lesenswert?

Johann L. schrieb:
> auch "anzeigen" lassen:

Und in C++ ganz ohne Warnung prüfen.
is_same<decltype(4711),const int>()
(oder ähnlich)

von Rolf M. (rmagnus)


Lesenswert?

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".

von A. S. (Gast)


Lesenswert?

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.

von Matthias T. (matthiasthiele)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

von A. S. (Gast)


Lesenswert?

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)

von Kernigham & Ritchie (Gast)


Lesenswert?

A. S. schrieb:
> Und 0xFFFF etwas anderes als 65535.
??? ??? ??? ??? ??? ??? ??? ??? ??? ???

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Kernigham & Ritchie schrieb:
> A. S. schrieb:
>> Und 0xFFFF etwas anderes als 65535.
> ??? ??? ??? ??? ??? ??? ??? ??? ??? ???

0xffff ist unsigned int.

65535 ist long int.

von Kernigham & Ritchie (Gast)


Lesenswert?

Hex und Dezimal sind nur andere Darstellungsformen zum Lesen. Warum sind 
das unterschiedliche Datentypen?

von Rolf M. (rmagnus)


Lesenswert?

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.

von MaWin (Gast)


Lesenswert?

C ist vollkommen bescheuert definiert. Wer hätte es gedacht.

von Kernigham & Ritchie (Gast)


Lesenswert?

Getestet. Es stimmt also das
0xFFFF >> HEX ist uint16_t
65535  >> DEZ ist int32_t

Dafür fehlt mir jede Art der Logik.

von MaWin (Gast)


Lesenswert?

Kernigham & Ritchie schrieb:
> Dafür fehlt mir jede Art der Logik.

Ist doch konsistent mit dem Rest von C.

von Kernigham & Ritchie (Gast)


Lesenswert?

Du meinst Unlogik ist Programm? Durchaus.

von A. S. (Gast)


Lesenswert?

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
int i=-1;
2
unsigned int u = 4;
3
4
   if(i<u) {doit();} /*warum wird doit nie aufgerufen  ???*/

von EAF (Gast)


Lesenswert?

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!
1
c:\#####\test.c: In function 'test':
2
c:\#####\test.c:10:7: warning: comparison of integer expressions of different signedness: 'int' and 'unsigned int' [-Wsign-compare]
3
   10 |   if(i<u) {doit();} /*warum wird doit nie aufgerufen  ???*/
4
      |       ^

von Gerd (Gast)


Lesenswert?

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".
1
// https://www.mikrocontroller.net/topic/548660
2
3
#define LIMIT_LOW -65535
4
#define LIMIT_HIGH 65535
5
6
const uint8_t P = 1;
7
8
int32_t P_controller(int32_t e)
9
{
10
  int32_t P_Teil;
11
12
  P_Teil = P * e;
13
14
  if (P_Teil < LIMIT_LOW) P_Teil = LIMIT_LOW;
15
  if (P_Teil > LIMIT_HIGH) P_Teil = LIMIT_HIGH;
16
17
  return P_Teil;
18
}
19
20
void setup()
21
{
22
  Serial.begin(115200);
23
}
24
25
int32_t T_ist = 0;
26
int32_t T_soll = -1000;
27
28
void loop()
29
{
30
  int32_t e;
31
32
  e = T_soll - T_ist;
33
  T_ist = P_controller(e);
34
  
35
  Serial.println(T_ist);
36
  delay(100);
37
38
}

von Rolf M. (rmagnus)


Lesenswert?

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.

von MaWin (Gast)


Lesenswert?

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.

von So macht es die KI (Gast)


Lesenswert?

#include <avr/io.h>
#include <avr/interrupt.h>

#define Kp 1.0 // Proportional gain
#define dT 0.1 // Timestep (seconds)
#define PWM_FREQUENCY 500 // PWM frequency (Hz)
#define PWM_RANGE 100 // PWM range (0-100)

float proportional_control(float setpoint, float measured_value)
{
    float error = setpoint - measured_value;
    return Kp * error;
}

int main()
{
    float setpoint = 50.0; // Setpoint (rpm)
    float measured_value = 45.0; // Measured value (rpm)

    // Set up Timer1 for PWM generation
    TCCR1A |= (1 << WGM10) | (1 << WGM11); // Fast PWM mode
    TCCR1B |= (1 << WGM12) | (1 << WGM13);
    TCCR1A |= (1 << COM1A1); // Non-inverting mode
    TCCR1B |= (1 << CS10); // No prescaler
    OCR1A = 0; // Initial PWM duty cycle
    ICR1 = F_CPU  PWM_FREQUENCY  PWM_RANGE; // Set PWM frequency

    // Enable global interrupts
    sei();

    while (1)
    {
        // Calculate control signal
        float control_signal = proportional_control(setpoint, 
measured_value);

        // Set PWM duty cycle
        OCR1A = (uint16_t)(control_signal * PWM_RANGE);

        // Sleep for timestep dT
        _delay_ms(dT * 1000);
    }

    return 0;
}

von Gerd (Gast)


Lesenswert?

> 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 ...

von MaWin (Gast)


Lesenswert?

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.

von So macht es die KI (Gast)


Lesenswert?

ChatGPT mit Integer

#include <avr/io.h>
#include <avr/interrupt.h>

#define Kp 100 // Proportional gain
#define dT 100 // Timestep (milliseconds)
#define PWM_FREQUENCY 500 // PWM frequency (Hz)
#define PWM_RANGE 100 // PWM range (0-100)

int proportional_control(int setpoint, int measured_value)
{
    int error = setpoint - measured_value;
    return Kp * error / 100;
}

int main()
{
    int setpoint = 5000; // Setpoint (rpm)
    int measured_value = 4500; // Measured value (rpm)

    // Set up Timer1 for PWM generation
    TCCR1A |= (1 << WGM10) | (1 << WGM11); // Fast PWM mode
    TCCR1B |= (1 << WGM12) | (1 << WGM13);
    TCCR1A |= (1 << COM1A1); // Non-inverting mode
    TCCR1B |= (1 << CS10); // No prescaler
    OCR1A = 0; // Initial PWM duty cycle
    ICR1 = F_CPU  PWM_FREQUENCY  PWM_RANGE; // Set PWM frequency

    // Enable global interrupts
    sei();

    while (1)
    {
        // Calculate control signal
        int control_signal = proportional_control(setpoint, 
measured_value);

        // Set PWM duty cycle
        OCR1A = control_signal * PWM_RANGE / 100;

        // Sleep for timestep dT
        _delay_ms(dT);
    }

    return 0;
}

von So macht es die KI (Gast)


Lesenswert?

Hab es nicht compiliert….

von Gerd (Gast)


Lesenswert?

>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.

von Matthias T. (matthiasthiele)


Lesenswert?

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...

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


Lesenswert?

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
    return Kp * 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.

: Bearbeitet durch Moderator
von MaWin (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von So macht es die KI (Gast)


Lesenswert?

Proportionalregler in ansi c code

Bitte für Atmel AVR Controller

Bitte mit Integer statt float….

von Matthias T. (matthiasthiele)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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

von MaWin (Gast)


Lesenswert?

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.

von J. S. (jojos)


Lesenswert?

Man kann die KI auf Fehler hinweisen und die schafft es auch die zu 
korrigieren, siehe das ct uplink 3003 Video.

von MaWin (Gast)


Lesenswert?

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.

von Teo D. (teoderix)


Lesenswert?

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

von Stefan F. (Gast)


Lesenswert?

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.

von MaWin (Gast)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

: Bearbeitet durch Moderator
von MaWin O. (mawin_original)


Lesenswert?

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.

Beitrag #7309372 wurde von einem Moderator gelöscht.
von Stefan F. (Gast)


Lesenswert?

Da dieses ChatGPT Thema hier off-topic ist, habe ich mene Antwort 
dorthin verschoben: Beitrag "Re: AI mit ChatGPT"

von Matthias T. (matthiasthiele)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

Yalu X. schrieb:
> 3*30000 auf einem 16-Bit-System ist ohnehin undefined

Warum?

Oliver

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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?

von Kernigham & Ritchie (Gast)


Lesenswert?

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

von MaWin O. (mawin_original)


Lesenswert?

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.

von Kernigham & Ritchie (Gast)


Lesenswert?

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.

von MaWin O. (mawin_original)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von MaWin O. (mawin_original)


Lesenswert?

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).

Beitrag #7309474 wurde vom Autor gelöscht.
von Kernigham & Ritchie (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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

von MaWin O. (mawin_original)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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.

von MaWin O. (mawin_original)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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.

von MaWin O. (mawin_original)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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"

von c-hater (Gast)


Lesenswert?

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...

von El Capitan (Gast)


Lesenswert?

c-hater schrieb:
> alles
> darüber mit RICHTIGEN Hochsprachen.

Welche nutzt Du für AVR/ESP/STM32?

von MaWin O. (mawin_original)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Justin S. (Gast)


Lesenswert?

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.

von Kernigham & Ritchie (Gast)


Lesenswert?

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.

von MaWin O. (mawin_original)


Lesenswert?

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.

von Kernigham & Ritchie (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von MaWin O. (mawin_original)


Lesenswert?

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.

von Kernigham & Ritchie (Gast)


Lesenswert?

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.

von MaWin O. (mawin_original)


Lesenswert?

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?"

von MaWin O. (mawin_original)


Lesenswert?

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.

: Bearbeitet durch User
von Gerd (Gast)


Lesenswert?

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

von MaWin O. (mawin_original)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von MaWin O. (mawin_original)


Lesenswert?

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.

von kleiner Admin (Gast)


Lesenswert?

> 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.

von Kernigham & Ritchie (Gast)


Lesenswert?

@ 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.

von MaWin O. (mawin_original)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von Dirk B. (dirkb2)


Lesenswert?

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.

von EAF (Gast)


Lesenswert?

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

von Matthias T. (matthiasthiele)


Lesenswert?

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.

von MaWin O. (mawin_original)


Lesenswert?

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.

: Bearbeitet durch User
von El Capitan (Gast)


Lesenswert?

Stefan F. schrieb:
> Alles, was er nicht in Assembler programmieren kann, programmiert er gar
> nicht. Also fast alles, offenbar.

DICH habe ich nicht gefragt!

von Stefan F. (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

: Bearbeitet durch User
von MaWin O. (mawin_original)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

: Bearbeitet durch User
von MaWin O. (mawin_original)


Lesenswert?

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.

: Bearbeitet durch User
von Matthias T. (matthiasthiele)


Lesenswert?

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.

von MaWin O. (mawin_original)


Lesenswert?

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.

von EAF (Gast)


Lesenswert?

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)

von MaWin O. (mawin_original)


Lesenswert?

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.

von Matthias T. (matthiasthiele)


Lesenswert?

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.

von Markus F. (mfro)


Lesenswert?

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.

von MaWin O. (mawin_original)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

: Bearbeitet durch User
von EAF (Gast)


Lesenswert?

MaWin O. schrieb:
> Bei der Warnung geht es nicht darum, ob der Operator atomar ist,

Beispiel:
1
 #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))


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.

von MaWin O. (mawin_original)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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…

von Matthias T. (matthiasthiele)


Lesenswert?

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?

von MaWin O. (mawin_original)


Lesenswert?

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.

von MaWin O. (mawin_original)


Lesenswert?

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.

von Matthias T. (matthiasthiele)


Lesenswert?

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.

von MaWin O. (mawin_original)


Lesenswert?

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.

von Matthias T. (matthiasthiele)


Lesenswert?

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".

von Markus F. (mfro)


Lesenswert?

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++.

von Yalu X. (yalu) (Moderator)


Lesenswert?

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:
1
#include <stdio.h>
2
3
int main(void) {
4
  for (int i = 0; i != -1; i++)
5
    printf("loop\n");
6
}

von Markus F. (mfro)


Lesenswert?

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
1
In function ‘main’:
2
tst014.c:3:29: warning: iteration 2147483647 invokes undefined behavior [-Waggressive-loop-optimizations]
3
    3 |   for (int i = 0; i != -1; i++)
4
      |                            ~^~
5
tst014.c:3:21: note: within this loop
6
    3 |   for (int i = 0; i != -1; i++)
7
      |                   ~~^~~~~
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...

von Oliver S. (oliverso)


Lesenswert?

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

von Markus F. (mfro)


Lesenswert?

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]

Dahinter steckt derselbe Compiler.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von Purzel H. (hacky)


Lesenswert?

> 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.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

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

von Purzel H. (hacky)


Lesenswert?

Man muss natuerlich alle Kombinationen abdecken.

Beitrag #7310746 wurde von einem Moderator gelöscht.
von Stefan F. (Gast)


Lesenswert?

EAF schrieb:
> denn ich weiß, dass |= nicht atomar ist

Wen man damit ein einzelnes Bit in SFR <= 0x1F setzt, macht er eine 
atomare SBI Operation:
1
#include <avr/io.h>
2
3
int main() 
4
{
5
   PORTB |= 1;
6
}

avr-gcc -mmcu=atmega328 -O1 test.c
avr-objdump -h -S a.out
1
00000080 <main>:
2
  80:  28 9a         sbi  0x05, 0  ; 5
3
  82:  80 e0         ldi  r24, 0x00  ; 0
4
  84:  90 e0         ldi  r25, 0x00  ; 0
5
  86:  08 95         ret

von EAF (Gast)


Lesenswert?

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!

von Stefan F. (Gast)


Lesenswert?

>> Wenn man damit ein einzelnes Bit in SFR <= 0x1F setzt, macht er eine
>> atomare SBI Operation

EAF 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.

von EAF (Gast)


Lesenswert?

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.

von Sermon (Gast)


Lesenswert?

Dieser Stefan F ist manchmal unerträglich.
Der muss Senf ohne Ende sein Eigen nennen.

von Kernigham & Ritchie (Gast)


Lesenswert?

Das Thema "volatile deprecated" wurde schon einmal ausführlich 
behandelt.
Beitrag "avr-gcc-10 - "volatile deprecated [-Wvolatile]" Warnungen"

von ⚡Guido⚡ (guido_hat_euch_lieb)


Lesenswert?

El Capitan schrieb:
> Welche nutzt Du für AVR/ESP/STM32?

Pascal:-)
Kein Scherz

von S.E. (Gast)


Lesenswert?

⚡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?

von Stefan F. (Gast)


Lesenswert?

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.

von ⚡Guido⚡ (guido_hat_euch_lieb)


Lesenswert?

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

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.