Hallo.
Kann mir kurz jemand erklären ob das wirklich stimmt was mir ChatGPT gesagt hat?
Stimmt diese Rechnung:
unsigned long var1 = 100;
var1 += 86400UL;
?
Muss ich immer bei jeder Zahl in jeder Rechnung die grösser ist als int beinhalten kann (32'767) UL dahinter schreiben, damit es nicht standardmässig als int berechnet wird, sonder als unsigned long?
Also immer wenn ich irgendwo etwas rechne, mit Zahlen die grösser als 32'767 sind, muss ich z.B. UL dahinter anhängen, damit es richtig funktioniert?
Gilt das auch für dieses Beispiel:
unsigned long var1 = 123456UL + 123456UL;
?
Gibt es keine einfachere möglichkeit am Anfang alles als unsigned long zu deklarieren, z.B. eben durch
>unsigned long< var1 = 123456 + 123456;
(natürlich ohne die Pfeile), oder
unsigned long var1 = (unsigned long) 123456 + 123456;
?
Wäre nett wenn mir das kurz jemand erklären könnte.
Vielen Dank
ein Literal das schon größer ist als int, erzwingt nicht die Kennzeichnung.
Es geht darum dass wenn deine Berechnung größer werden kann als int, dass du dann mindestens einen Term benötigst der mind. so groß ist, wie das Ergebnis werden kann. Wenn du sonst keinen passend großen Term hast, kannst du das mit einem Literal machen.
void setup() {
Serial.begin(115200);
unsigned long var1 = 100;
var1 += 86400;
Serial.println(var1);
unsigned long var2 = 123456 + 123456;
Serial.println(var2);
// Zusatz
unsigned long var3 = 0;
int var4 = 36000;
var3 = var4 * 1000UL; // 36000 * 1000 wäre größer als int
Serial.println(var3);
}
void loop() {
// put your main code here, to run repeatedly:
}
Schalte dir die ausführlichen Compiler Warnings ein, dann weist dich der Compiler meist auf derartige Probleme hin.
?
Es wird mir leider nicht ersichtlich aus der von dir verlinkten Referenz...
Das mal zu combie, und ich sehe gerade das noiasca auch etwas dazu geschrieben hat, und da wird es irgendwie schon wieder unlogisch für mich...
Wie kann das sein:
unsigned long var1 = 100;
var1 += 86400;
unsigned long var3 = 0;
int var4 = 36000; // Wie kann int eine Zahl beinhalten die grösser als 32'767 ist?
var3 = var4 * 1000UL; // 36000 * 1000 wäre größer als int
Zur letzten Zeile mit var3, wieso muss ich dort in der Rechnung UL schreiben obwohl var3 schon als unsigned long deklariert wurde, und oben geht var1 += 86400 ohne UL? Genau das verstehen ich nicht, es erscheint mir unlogisch...
ja, weil, 86400 bereits zu groß fü ein int ( auf UNO ) ist.
nein, weil beide Elemente des Ausdrucks in ein int passen.
[Edit] Ups - 36000 passt auch bereits nicht in ein int (int ist ja vorzeichenbehaftet) - sollte also auch funktionieren.[/Edit]
Eigentlich ist es recht einfach: Die Berechnung auf der rechten Seite wird immer als int ausgeführt, solange alle einzelnen Elemente des Ausdrucks als int dargestellt werden können. Nur wenn bereits aus einem einzelnen Element ersichtlich ist, dass das größer als int ist, wir die Berechnung als long ausgeführt. Das kann entweder dadurch sein, dass der Zahlenwert bereits zu groß für ein int ist, durch ein angehangtes Suffix (z.B. UL) der Wert als long/unsigned long gekennzeichnet ist, oder dass der Ausdruck eine Variable enthält, die entsprechend deklariert wurde.
Der Typ der Variable, der das Ergebnis dann zugewiesen wird, ist unerheblich, denn das passiert erst nach der Berechnung.
Ausschlaggebend ist der verbaute µC, beim Uno R3 der ATmega328P, der auch beim Nano und ProMini verwendet wird. Daher entspricht der Typ int zweimal der ALU-Breite, also 2 * 8 = 16 Bit.
Die Spannung hat eventuell Einfluß auf den Takt, aber nicht auf die Berechnungen.
Ok. Vielen Dank allen für die Hilfe, ich glaube ich verstehe es jetzt in etwa.
Der zentrale Punkt um den sich alles dreht scheint das zu sein:
Bedeutet: Wenn eine Zahl in der Rechnung (rechts vom =) nicht in einen int passt, erkennt das der Compiler oder Arduino, und behandelt die Zahl automatisch als z.B. long wenn sie da hinein passt (und dann wird auch das Ergebnis als long behandelt). Aber das Ergebnis wird nicht vorher überprüft ob es in einen int passt, was dazu führen kann dass wenn 2 int Operanden als Ergebnis nicht mehr in einen int passen, es überläuft noch bevor es erkannt wird dass es zu klein ist.
Das erscheint mir wie ein Logik Fehler im Compilierer oder Arduino, aber irgendwie ist das halt so, ging wahrscheinlich nicht so einfach anders im Aufbau der ganzen Technik.
Somit sollte jetzt alles klar sein, und ich werde schauen ob das bei meinen Scripten alles aufgeht und ob der Compiler eine Fehlermeldung ausgiebt.
Edit: Ja, du hast es weiter unten noch genauer erklärt, ich habe es weg gelassen weil ich meine Antwort kompakter halten wollte, weil schon ziemlich viel rund um diese Problem dass ich nicht verstanden habe geschrieben wurde:
Und ah ja, z.B. bei unsigned long kann der Überlauf gewollt sein... Dann macht es mehr Sinn, erscheint nur ziemlich verwirrend auf den 1. Blick...
Compiler werden von Menschen gemacht und die haben bestimmte Vorstellungen, was der können soll und was nicht.
In Basic hat a = 5 den Typ bestimmt, also der Typ rechts vom Gleichheitszeichen bestimmte den Typ der Variablen links davon. Ich habe den Eindruck, nach sowas suchst Du. Bei C muß man den Typ aber explizit angeben. Beim Umstieg kann es schonmal zu Konflikten kommen. Man muß sich halt auf die Ideen der Entwickler einlassen, geht nicht anders.
Wenn es Dich beruhigt, daß rechts vom Gleichheitszeichen unabhängig vom Typ der Variablen links davon gerechnet wird, habe ich zunächst auch nicht gewußt. Aber spätestens, wenn man auf die Nase fällt, kümmert man sich darum.
Nur noch mal erwähnen möchte ich, daß man zwischen syntaktischen Fehlern, die der Compiler erkennen kann, und Laufzeitfehlern unterscheiden muß.
Ein Beispiel ist der Überlauf nach etwas mehr als 49 Tagen von millis(). Bei Langläufern muß man das berücksichtigen, was aber kein Problem ist.
Ja das stimmt schon, es wird wahrscheinlich daran liegen, das ein Mensch eine Vorstellung hatte und dann halt mit den möglichen Mittel etwas kreiert hat.
Und ja das mit dem Überlauf bei millis(), der in einer bestimmten Rechnungsweise kein Problem macht, meinte ich auch.