Damit das statische Codeanalyse-Tool nicht "implicit conversion from
signed literal to unsigned literal" moniert.
Und sonst ist es sauberes Arbeiten von dir als Entwickler. Du hast damit
dokumentiert, dass du weißt, dass diese Variable vorzeichenlos ist.
mfg mf
Lars schrieb:> dummschwaetzer schrieb:>> guter Style>> ja vielleicht, aber wofür steht das u?> der typ steht ja schon davor.
Nein, steht er nicht. Der Typ steht vor der und gilt für die Variable,
der der Wert zugewiesen wird. Deine Beispiele oben sind falsch, da fehlt
diese.
Oliver
Lars schrieb:> ja vielleicht, aber wofür steht das u?
Für eine vorzeichenlose Konstante.
> der typ steht ja schon davor.
Nein, das ist der Typ des Ergebnisses der Zuweisung. Wenn du rechts das
u weglässt, ist die rechte Seite erst einmal "int".
Lars schrieb:> z.B.> uint8_t 0x0Au;> uint8_t 8u;
Du meinst vermutlich eher so etwas wie
uint8_t minutes = 42u;
Das u bedeutet, dass das 42 explizit unsigned ist. Je nach Coding
Standard ist das erforderlich und in sehr vielen Fällen auch sinnvoll.
Anders als oben beschrieben handelt es sich NICHT nur um eine optische
Sache.
Es gibt Fälle, bei denen die erzeugten Instructions sich unterscheiden
und auch die Performance besser sein kann. Das passiert, wenn Konstanten
mit "u" in Formeln auftauchen. Wenn dem Compiler bewusst ist, dass eine
Konstante unsigned ist und damit auch das Ergebnis unsigned ist kann
teils auf Rechenschritte verzichtet werden.
Ein Beispiel bei mir aus dem echten Leben:
imgBuf[sBase+4] |= (cl & 0x20u) ? sBaseCol8 : 0;
(alles 8-bit Werte, unsigned). Was das macht ist erstmal unerheblich.
Effizienter ist aber:
imgBuf[sBase+4] |= (cl & 0x20u) ? sBaseCol8 : 0u;
Grund: Es gibt eine Signed und Unsigned 0. Im ersteren Fall "muss" eine
sign-extension durchgeführt werden, im letzteren Fall nicht. Spart eine
Instruktion.
Johannes O. schrieb:> Im ersteren Fall "muss" eine sign-extension durchgeführt werden
Stimmt so auch nicht. Bei einer Konstanten muss der Compiler so einen
Zirkus ja nicht machen, denn dass sich dadurch am Ergebnis nichts
ändert, ist ihm von vornherein klar. Die 0 hat sowohl im Datentyp "int"
als auch "unsigned int" das gleiche Bitmuster.
Lars schrieb:> warum schreibt man eigentlich hinter dem wert von einer unsigned> variablen nochmal ein u?
Aus den selben Grund wieso ich hinter ein String ein $ mache. Es ist
zwar in moderne Basic nicht mehr nötig, aber mir hilft es den
Unterschied zwischen String + Zahl festzustellen.
Bei Basic muss ich entweder ein $ machen wenn ich die Variable das erste
mal benutze oder DIM variable (ohne $) as String eingeben.
Ich finde wenn man größere Programme schreibt es sehr hilfreich wenn man
sich so was angewöhnt. Das mache ich sogar mit Objekten. hp_a_feld.
Dann weiss ich genau es kommt vom der Hauptform und ist ein Anzeigefeld
(Label).
Glaub mir wenn du dir so was angewöhnst kannst du locker 5 x schneller
Programmieren. Besonders dann wenn der Editor Vorblendungen unterstützt.
Und für alle die lästern. In C + Co. ist es bei mir absolut das gleiche.
Jörg W. schrieb:> Johannes O. schrieb:>> Im ersteren Fall "muss" eine sign-extension durchgeführt werden>> Stimmt so auch nicht. Bei einer Konstanten muss der Compiler so einen> Zirkus ja nicht machen, denn dass sich dadurch am Ergebnis nichts> ändert, ist ihm von vornherein klar. Die 0 hat sowohl im Datentyp "int"> als auch "unsigned int" das gleiche Bitmuster.
Daher auch das "muss" in Anführungszeichen, bei mir hat er sich dafür
entschieden.
Auf was ich raus wollte ist: Das u wird vom Compiler durchaus
wahrgenommen und kann einen Einfluss aufs Ergebnis haben.
Johannes O. schrieb:> Auf was ich raus wollte ist: Das u wird vom Compiler durchaus> wahrgenommen und kann einen Einfluss aufs Ergebnis haben.
$ zeichen beim VB-Compiler auch. Der erkennt sogar wenn man es vergessen
hat, falls man es einmal benutzt hat. Die erste Variante der Variable
zählt.
Viel lustiger ise ein kleines l hinter einer Konstanten.
Dazu vllt noch eine unscheinbare 0 davor.
So ein 0111l foerdert doch das Denken des Betrachters ungemein.
Man muss es den Junkspunten ja nicht unnoetig leicht machen.
Lars schrieb:> z.B. uint8_t 0x0Au; uint8_t 8u;
Die Beispiele sind aber schräg (und falsch).
Viel wichtiger ist es bei #defines und bei Berechnungen (falls Du das
meinst)
Schlaumaier schrieb:> Und für alle die lästern. In C + Co. ist es bei mir absolut das gleiche.
Naja, dass die Hungarian Notation mehr Nachteile als Vorteile hat ist ja
kein "Laestern", das macht man heute im allgemeinen nicht mehr so, aus
Guten Gruenden.
Wenn dir das hilft ist das ja okay, in grossen Projekten ist das
allerdings ein no-go und wird auch nicht mehr gemacht, seit sehr langer
Zeit.
Mladen G. schrieb:> Wenn dir das hilft ist das ja okay,
Es hilft mir sogut, das ich sogar die Objekte mit so Codes (als Name)
versehen habe. Obwohl das nirgends vorschrift ist.
Die Hauptform heißt HP
Ein Button auf den Hauptform für berechnen heisst. hp_b_berechnen
Eine anfrage besteht i.d.R. aus 2 feldern.
Label-Feld = hp_a_strasse
Text-Feld = hp_e_strasse
Das hat in meinen Augen gigantische Vorteile gerade bei mehr als "Hello
World". Der Grund : Ich weiß genau WO der Button ist, ich weiss DAS es
ein Button ist, und keine Variable. Und ich weiß welche Funktion er hat.
Ich lese z.b. das in einer Form das Eingabefeld einer anderen Form aus.
Da ich die Namen meiner Forms alle im Kopf habe, finde ich dank
Vorblendung genau was ich brauche.
Außer der viel besseren Übersicht, hat es auch den Vorteil das man
Textblöcke kopieren kann, und nur durch austauschen eines Buchstabens
ein anderes Objekte hat. Das ist besonders dann interessant, wenn man
Objekte zu Array bündeln will. ;)
Und meine Projekte haben aktuell bis zu 45 Forms, und jede Menge
Objekte. Tendenz steigend, weil oft neue Funktionen auch neue Forms
erfordern.
Ich habe sie nie gezählt. ;)
Aber ich bin auch heilfroh das ich nur selbst entwickele und nicht in
einen Thema wo man sich auch irgendwelche teils schwachsinnigen Regeln
halten muss. Allerdings schicke ich auch keinen Bug-Fixes raus. Weil ich
bei meiner Software den Durchblick habe. ;)
Hallo,
Jörg W. schrieb:> Wenn du rechts das u weglässt, ist die rechte Seite erst> einmal "int".
Verstehe ich nicht.
Der Compiler 'weiß' doch das der konstante Wert einer vorzeichenlosen
Variable zugewiesen werden soll. Da kann er doch auch direkt annehmen
das die Konstante vorzeichenlos ist. Wieso nimmt er an das die rechte
Seite erst mal int (also vorzeichenbehaftet) ist?
rhf
Vorschrift ist das sowieso nicht, sind ja nur Konvention.
Bei der sog. "Hungarian Notation" geht es darum, den Typ in den Namen
der Variablen einfliessen zu lassen, also Redundanz.
In grossen Systemen hat man damit sehr schlechte Erfahrungen gemacht,
als Beispiel sei die Win32 API genannt, wo der prefix no i war, aber der
Typ schon long, ist halt ein grundsaetzliches Problem der Redundanz.
Brauchen tut man die Hungarian Notation mit Typecheck nicht wirklich,
und ansonsten uebernehmen moderne IDEs das, die zeigen dir gleich
welcher Typ das ist.
Das und andere Gruende haben dafuer gesorgt, dass man von der Hungarian
Notation abraet, seit mind. 20 Jahren oder so.
Wenn du das alleine machst kannst du dir natuerlich aussuchen wie du
Dinge benamst, wenn das fuer dich funktioniert, ist das ja auch okay.
Entwickler bei UBER zB. mussten schon vor 3-4 Jahren mit ueber
zehntausend Git Repos lokal arbeiten koennen (MicroServices), in so
einem Kontext muessen Konventionen anders entschieden werden, bestimmte
Dinge werden strikter, andere wiederum lockerer..
Roland F. schrieb:> Wieso nimmt er an das die rechte Seite erst mal int (also> vorzeichenbehaftet) ist?
Weil int Default ist. Ist ja nicht schlimm. Schlimm wird's erst, wenn
man damit vor der Zuweisung rechnet
Roland F. schrieb:> Der Compiler 'weiß' doch das der konstante Wert einer vorzeichenlosen> Variable zugewiesen werden soll.
Er könnte es wissen, es hat ihn aber per Sprachdefinition nicht zu
interessieren, Die rechte Seite einer Zuweisung wird völlig eigenständig
betrachtet. Erst mit der Zuweisung selbst wird an den Typ links
angeglichen.
Roland F. schrieb:> Der Compiler 'weiß' doch das der konstante Wert einer vorzeichenlosen> Variable zugewiesen werden soll. Da kann er doch auch direkt annehmen> das die Konstante vorzeichenlos ist.
Nein, die Berechnung eines Ausdrucks hat erst einmal Datentypen, die
sich nach den Elementen des Ausdrucks richten. Erst bei der Zuweisung
wird der Datentyp der linken Seite betrachtet.
Allerdings hast du mit dem "der weiß das doch" insofern Recht, dass es
die "as if"-Regel gibt: der Compiler muss das erzeugen, was in der
zugrunde gelegten abstrakten Maschine passiert, wenn man die Regeln so
anwendet. Wenn er dabei bemerkt, dass die Information, dass die
Konstante 0x0a vom Typ "int" ist, in diesem Zusammenhang gegenstandslos
wird (bei der einfachen Zuweisung ohne Verkürzung der Bitanzahl wie hier
ist das praktisch immer der fall), dann kann er auch irgendwelche Dinge
weglassen wie beispielsweise die Betrachtung eines nicht vorhandenen
Vorzeichens.
Insofern hat das Anhängen eines "u" in solch simplen Fällen wie hier
wirklich nur einen Dokumentations-Zweck (entweder gegenüber humanen
Lesern des Programms oder, wie schon genannt, gegenüber
Analyse-Programmen, um ihnen mitzuteilen, dass dem Schreiber des Codes
klar war, dass die Konstante eine vorzeichenlose Zahl darstellt).
Hallo,
Jörg W. schrieb:> Nein, die Berechnung eines Ausdrucks hat erst einmal Datentypen, die> sich nach den Elementen des Ausdrucks richten. Erst bei der Zuweisung> wird der Datentyp der linken Seite betrachtet.> ...
Danke für die Erklärung, ich habe das jetzt so weit verstanden. Ich
wundere mich nur das selbst heutige Compiler (noch) nicht "schlau" genug
sind so was selber zu erkennen. Erstaunlich, das die überall um sich
greifende "künstliche Intelligenz" bei Compilern noch nicht so richtig
angekommen ist.
rhf
Roland F. schrieb:> Danke für die Erklärung, ich habe das jetzt so weit verstanden. Ich> wundere mich nur das selbst heutige Compiler (noch) nicht "schlau" genug> sind so was selber zu erkennen.
Doch, sind sie.
Aber die Definition der Sprache betrachtet halt zuerst einmal den
Ausdruck der rechten Seite. Der kann ja deutlich komplexer sein als die
einfache Konstante hier, und der hat eben einen Datentypen.
Nach der Zuweisung ergibt sich übrigens auch wieder ein Ausdruck, den
kann man auch wieder auf der rechten Seite einer Zuweisung benutzen, und
der hat dann einen Datentypen, der durch die zuvor linke Seite bestimmt
wird.
Also:
1
intx;
2
unsignedy;
3
4
x=y=42;
Die 42 hat den Datentyp "int". Mit der Zuweisung auf y wird der Datentyp
"unsigned". Beide Typen sind problemlos zuweisungskompatibel. Auf der
rechten Seite der Zuweisung an x steht jetzt ein "usigned"-Operand, der
durch die Zuweisung dann wieder in "int" gewandelt wird.
Dass sich in all diesen Fällen am Bitmuster für die 42 nichts ändert,
erkennt der Compiler selbstverständlich, aber formal sind es eben
erstmal verschiedene Datentypen, und das eine oder andere Tool für eine
statische Codeanalyse könnte dich auf deinen Typ-Mischmasch hinweisen
wollen.
Roland F. schrieb:> Ich wundere mich nur das selbst heutige Compiler (noch) nicht "schlau"> genug sind so was selber zu erkennen.
Abgesehen davon, dass das auch die ersten Compiler hätten erkennen
können: mir ist ein eindeutiges Verhalten lieber als ein schlaues.
Zumal Du ja auch einfach die Warnungen einschalten kannst.
Jeder Anfänger schimpft dann auf seinem Compiler, dass der nicht gleich
die Klammer-Zu setzt, wenn er doch weiss, dass sie fehlt.
A. S. schrieb:> Jeder Anfänger schimpft dann auf seinem Compiler, dass der nicht gleich> die Klammer-Zu setzt, wenn er doch weiss, dass sie fehlt.
Naja, wer die Regeln kennt, weiß das es absolut unmöglich ist, die
Klammer vom PC schließen zu lassen. Der PC wird "hoffentlich" nie
wissen wo er die Klammer zu setzen hat. Dann kann er sich selbst
programmieren.
Und ich setze lieber eine Klammer die ich vergessen habe mal eben wegen
Syntax-Fehler als das ich wegen einer (vom PC) falsch gesetzten Klammer
stundenlang debugging machen muss, und alles mit den Taschenrechner
nachrechnen muss.
Roland F. schrieb:> Hallo,> Jörg W. schrieb:>> Wenn du rechts das u weglässt, ist die rechte Seite erst>> einmal "int".>> Verstehe ich nicht.> Der Compiler 'weiß' doch das der konstante Wert einer vorzeichenlosen> Variable zugewiesen werden soll. Da kann er doch auch direkt annehmen> das die Konstante vorzeichenlos ist. Wieso nimmt er an das die rechte> Seite erst mal int (also vorzeichenbehaftet) ist?
Der Compiler betrachtet jeden Ausdruck für sich und gibt ihm einen Typ,
der nur von diesem Ausdruck selbst abhängt und von nichts anderem - auch
nicht davon, was man später mal damit macht. Und wenn da eine 8 steht,
ist die laut C-Regeln vom Typ int. 8u ist dagegen vom Typ unsigned int.
Erst dann geht's mit der Verarbeitung los. Wenn da also steht:
1
uint8_tx=8;
Dann steht rechts vom = ein int, weil 8 vom Typ int ist. Links davon
steht aber ein uint8_t, also muss eine Konvertierung durchgeführt
werden. Die 8 wird also erst nach uint8_t konvertiert, und das Ergebnis
dieser Konvertierung wird dann als Initialisierungswert für x verwendet.
Wie man sieht, ist die Regel "8 ist vom Typ int" sehr einfach im
Vergleich dazu wenn es heißen müsste: "8 ist vom Typ int, es sei denn,
es wird damit eine Variable initialisiert, dann wird der Typ dieser
Variablen verwendet und 8 ist dann von diesem Typ. Wenn aber …". Das
wäre eine Kontextabhängigkeit, und die versucht man in
Programmiersprachen zu vermeiden wenn möglich, da sie die Regeln
komplizierter machen und damit es einerseits dem Compilerbauer
erschweren und andererseits für den Benutzer schwieriger machen zu
erkennen, was wirklich genau passiert.
Mladen G. schrieb:> Bei der sog. "Hungarian Notation" geht es darum, den Typ in den Namen> der Variablen einfliessen zu lassen, also Redundanz.
Gerade das war eigentlich nicht die Absicht dahinter. Das war nur eine
Fehlinterpretation von Microsoft, die dann alle so übernommen haben. Die
eigentliche Idee war, damit nicht den Datentyp, sondern die Art der
Daten zu kennzeichnen, also z.B. ob die Variable eine Geschwindigkeit,
eine Koordinate
oder eine Anzahl enthält.
Siehe https://de.wikipedia.org/wiki/Ungarische_Notation
Schlaumaier schrieb:> Ein Button auf den Hauptform für berechnen heisst. hp_b_berechnen
Du benutzt ernsthaft in Deinen Programmen Bezeichner in einer Sprache,
von der nicht der komplette Zeichensatz unterstützt wird? grusel
Nachdenklicher schrieb:> Du benutzt ernsthaft in Deinen Programmen Bezeichner in einer Sprache,> von der nicht der komplette Zeichensatz unterstützt wird? *grusel*
Wie meinen?
Hallo,
Jörg W. schrieb:> Roland F. schrieb:>> Danke für die Erklärung, ich habe das jetzt so weit verstanden. Ich>> wundere mich nur das selbst heutige Compiler (noch) nicht "schlau" genug>> sind so was selber zu erkennen.>> Doch, sind sie.> ...
Jetzt habe ich es verstanden, danke.
rhf
Hallo,
Rolf M. schrieb:> Der Compiler betrachtet jeden Ausdruck für sich und gibt ihm einen Typ,> der nur von diesem Ausdruck selbst abhängt und von nichts anderem - auch> nicht davon, was man später mal damit macht.> ...
Auch dir danke für die Erklärung. Ich wunderte mich nur über eine, aus
meiner Sicht, gewisse "Kurzsichtigkeit" der Compiler. Vom Gefühl her
hätte ich erwartet, das zu Zeiten, in denen die Leute
Supercomputertechnik der 90er-Jahre in der Hosentasche tragen und
überall über Lösungen per künstlicher Intelligenz proklamiert werden,
Compiler "vorausschauender" agieren. Vermutlich ist das aber mit den
heute verwendeten Programmiersprachen (deren Grundlagen ja aus der
60er-Jahren stammen!) gar nicht so einfach zu lösen.
rhf
P.S. Ich finde solche Diskussionen immer wieder interessant, weil sie
Aspekte beleuchten, über die ich noch nie nachgedacht habe. So was zeigt
dann oft wie komplex doch scheinbar einfache Sachverhalte sind.
Jörg W. schrieb:> Wie meinen?
Gut. Es gibt offensichtlich einen (exotischen?) C-Compiler, der sowas
kann.
Die meisten können es jedoch nicht.
Ich danke Dir herzlich für die Nennung der Ausnahme, die die Regel
bestätigt. ;-)
Nachdenklicher schrieb:> Gut. Es gibt offensichtlich einen (exotischen?) C-Compiler, der sowas> kann.> Die meisten können es jedoch nicht.>> Ich danke Dir herzlich für die Nennung der Ausnahme, die die Regel> bestätigt. ;-)
clang ist alles, aber ganz sicher nicht exotisch oder eine Ausnahme.
Roland F. schrieb:> Compiler "vorausschauender" agieren.
Ein Compiler zerlegt in einem frühen Schritt den Programmcode in eine
Baumstruktur:
1
(a = b + c / d)
2
wird zu
3
=
4
a +
5
b /
6
c d
Das war auch in den 60ern und 70ern schon so. Es wäre auch damals kein
Problem gewesen, den Typ der linken Seite von "=" von oben nach unten
über den Baum zu stülpen. Es würde allerdings bedeuten, dass die gesamte
rechte Seite mit dem Typ der linken Seite im Auge berechnet werden muss,
womit die Typen von a und b Einfluss auf die Breite der Division
bekommen.
Bei einfachen Ausdrücken wäre das zwar nicht immer effizient, aber noch
halbwegs übersichtlich. Das ändert sich in komplexeren Ausdrücken,
besonders bei Präprozessor-Makros wie
1
#define P(x,y) (x >> y)
Da es sich dabei um reine Textersetzung handelt, würde die Berechnung
innerhalb der Definition von P nicht mehr nur abhängig von den Typen von
x und y, sondern auch vom Kontext, in dem P verwendet wird. Also welche
Breite als Ergebnis von P erwartet wird.
Roland F. schrieb:> Vermutlich ist das aber mit den heute verwendeten Programmiersprachen> (deren Grundlagen ja aus der 60er-Jahren stammen!) gar nicht so einfach> zu lösen.
Naja, irgendwelche Regeln für Datentypen und deren (explizite oder
implizite) Umwandlungen brauchst du in der Sprache. Kannst ja mal
schauen, ob sich Rust da anders verhält. (Lieber nicht im
"Nachbar"-Thread fragen, der ist eh schon länglich genug. :)
Nachdenklicher schrieb:> Ich danke Dir herzlich für die Nennung der Ausnahme, die die Regel> bestätigt. ;-)
Clang als "exotische Ausnahme"? Mir dünkt, du hast die letzten
mindestens 10 Jahre Entwicklung verpennt.
Dass natürlich ein Programm, welches mehr als nur den portablen
Zeichensatz für seine Bezeichner benutzt, nicht mehr (im Sinne des
Standards) portabel ist, sollte offensichtlich sein. Das dürfte ein
wesentlicher Grund sein, warum viele Programmierer sich dahingehend
lieber einschränken.
Fortsetzung:
In C gehen bei (c / d) nur die Datentypen von c und d in die Rechnung
ein. Das Regelwerk dafür ist schon kompliziert genug, aber es hat nur 2
Parameter. Trotzdem stoplern viele darüber, woran allerdings auch die
Mindestbreite von "int" Schuld hat.
Geht jedoch auch der erwartete Typ des Gesamtausdrucks in das Regelwerk
mit ein, also die Breite der Addition in (a = b + c / d), die wiederum
von den Typen von a und b abhängen würde, bekäme das Regelwerk einen
weiteren Parameter, hätte nun also 3. Und der dritte ist vom
Programmierer nicht direkt erkennbar.
Statt dessen entwickeln sich in C die Datentypen von Berechnungen von
unten nach oben durch den Baum, nicht von oben nach unten. Die Typen von
c und d definieren die Art der Division, deren Ergebnis zusammen mit dem
Typ von b die Addition. Das hält die Sache übersichtlich.
Jörg W. schrieb:> Clang als "exotische Ausnahme"? Mir dünkt, du hast die letzten> mindestens 10 Jahre Entwicklung verpennt.
Auf der Arbeit bin ich tatsächlich mit einem mehr als 10 Jahre alten
ARM-Compiler unterwegs, weil man die Kosten für ein Upgrade vermeiden
möchte. Bei der Anzahl der zu aktualisierenden Lizenzen und dem Preis
selbiger wäre das eine sechsstellige Investition. Lebt man halt damit,
daß der nur C89 kann. ¯\_(ツ)_/¯
Privat arbeite ich ausschließlich mit gcc, sowohl für den PC (selten,
daß ich da mal mehr brauche als man mit einem schnellen Python-Script
erledigen könnte, aber falls doch...) als auch AVR. Den gibt es zwar
schon lange, aber als "Entwicklung verpennt" würde ich das nicht gerade
bezeichnen.
Nachdenklicher schrieb:> Bei der Anzahl der zu aktualisierenden Lizenzen und dem Preis> selbiger wäre das eine sechsstellige Investition. Lebt man halt damit,> daß der nur C89 kann.
Autsch.
> Den gibt es zwar> schon lange, aber als "Entwicklung verpennt" würde ich das nicht gerade> bezeichnen.
Bezüglich Clang halt schon. Der ist nun schon lange da und hat auch den
GCC schon ein wenig aufgemischt. Die Fehlermeldungen sind seither
nämlich auch dort viel aussagekräftiger geworden. ;-)
Ob und mit welcher Version man beim GCC auch als host character set mit
UTF-8 (in Bezeichner) arbeiten kann, habe ich auf die Schnelle nicht
rausgefunden. Selbst interessiert es mich eigentlich schon deshalb nicht
großartig, weil ich seit Jahrzehnten alle Programme komplett auf
Englisch schreibe, sowohl privat als auch dienstlich.
Jörg W. schrieb:> Autsch.
Ja, gefällt uns auch nicht. Unsere Hoffnung war, daß der Compiler nicht
unter Windows 10 funktioniert und das Management in Zugzwang kommt.
Leider vergebens, der läuft genauso gut wie vorher. (Mittlerweile nutze
ich wenigstens nur noch den Compiler und Debugger, der Code-Editor davon
-man traut sich nicht, das als IDE zu bezeichnen- ist grauenhaft. Aber
mit Visual Studio Code geht's.)
> Bezüglich Clang halt schon. Der ist nun schon lange da und hat auch den> GCC schon ein wenig aufgemischt. Die Fehlermeldungen sind seither> nämlich auch dort viel aussagekräftiger geworden. ;-)
Naja, never touch a running system (zumindest im Hinblick drauf, welchen
Compiler ich verwende, regelmäßig aktualisiert wird der schon). Da
außerhalb meiner Arbeit mein Fokus auf AVRs liegt (PC-Software zu
entwickeln ist einfach nicht mein Ding, schon gar nicht wenn man sich
Gedanken um die GUI machen muß), ist der GCC halt der Standardcompiler.
> Ob und mit welcher Version man beim GCC auch als host character set mit> UTF-8 (in Bezeichner) arbeiten kann, habe ich auf die Schnelle nicht> rausgefunden. Selbst interessiert es mich eigentlich schon deshalb nicht> großartig, weil ich seit Jahrzehnten alle Programme komplett auf> Englisch schreibe, sowohl privat als auch dienstlich.
Und gerade im letzten Satz kommen wir wieder so richtig gut überein. :-)
Ab dem Punkt, wo ich von "Programme abtippen" zu "selbst programmieren"
übergegangen bin, wurde alles Englisch, inklusive Kommentaren. Privat
schadet es nicht, und auf der Arbeit profitiere ich davon, daran gewöhnt
zu sein, hier ist es aufgrund des internationalen Teams notwendig.
Nachdenklicher schrieb:> Da außerhalb meiner Arbeit mein Fokus auf AVRs liegt (PC-Software zu> entwickeln ist einfach nicht mein Ding, schon gar nicht wenn man sich> Gedanken um die GUI machen muß), ist der GCC halt der Standardcompiler.
Wobei es inzwischen auch einen Clang-Port für AVR gibt. Habe ich mir
allerdings noch nicht angesehen. Da ich von Johann im Ohr habe, dass der
AVR-GCC vom Design her eher suboptimal ist, könnte es gut sein, dass der
Clang in dieser Hinsicht sogar besser performt.
Nachdenklicher schrieb:> Du benutzt ernsthaft in Deinen Programmen Bezeichner in einer Sprache,> von der nicht der komplette Zeichensatz unterstützt wird? grusel
Ja aber ich habe noch NIE eine Variable/Bezeichner mit einen
Sonderzeichen benannt. Die einzige Ausnahme ist der Unterstrich.Und das
gilt nicht nur für Programmcode sondern auch für Tabellen etc.
Der Grund ist einfach und in einer anderen Thread von mir schon genannt.
Ich habe neulich 3 Std. googlen dürfen weil ich nicht wusste wie man
eine SQL-Tabelle anspricht deren Namen ein Sonderzeichen enthielt.
Ja ich weiß das es inzwischen möglich ist. Aber ich bin noch einer der
8.3 Generation. Da geht dir ins Blut über was du darfst und was nicht.
Es gab/gibt auch Domains mit ä und ü. Nur sind die schneller
verschwunden als die Werbung sie angepriesen hat.
Wenn du so lange im Geschäft bist wie ich, dann nutzt du nur das
Minimale was möglich ist. Gibt auch nur Minimale Probleme.
Mir reicht schon der Ärger mit ASCII + UTF-8 sowie den Komma/Punkt
Theater. Glaubs mir.
Jörg W. schrieb:> Geringfügig besser als die 6-Zeichen-FORTRAN-Generation. ;-)
Danke. Ich habe auf einen ZX-81 mit 1 KILOBYTES Ram gelernt. Da wusste
bei uns im Umkreis keine Firma wie man Computer schreibt.
Und ich habe so einen FORTRAN-Kauderwelsch auf einem PDP-11-Clone
gelernt. Ich war heilfroh, als es dann einen Pascal-Compiler gab und man
endlich lesbare Programme schreiben konnte.
(Das Schnipsel hier stammt allerdings aus linpack, also tatsächlich
Code, der auch heute noch benutzt wird.)
Jörg W. schrieb:> Kannst ja mal schauen, ob sich Rust da anders verhält.
Ja, Rust verhält sich in diesem Belang grundsätzlich anders als C, denn
es hat im Gegensatz zu C:
- Kein implizites casting.
- Type inference.
Gerade letzteres ist genau das, was hier im Thread wohl von C erwartet
wird. Type inference ist allerdings noch viel mehr. Es bezieht sich
nicht nur auf die Typen links und rechts vom Gleichheitszeichen der
Zuweisung.
Jörg W. schrieb:> Geringfügig besser als die 6-Zeichen-FORTRAN-Generation
Aber schön waren die BASIC-Dialekte, deren Statements auf drei Zeichen
verkürzt werden konnten.
MaWin schrieb:> Jörg W. schrieb:>> Kannst ja mal schauen, ob sich Rust da anders verhält.>> Ja, Rust verhält sich in diesem Belang grundsätzlich anders als C, denn> es hat im Gegensatz zu C:> - Kein implizites casting.> - Type inference.>> Gerade letzteres ist genau das, was hier im Thread wohl von C erwartet> wird. Type inference ist allerdings noch viel mehr. Es bezieht sich> nicht nur auf die Typen links und rechts vom Gleichheitszeichen> der Zuweisung.
Hauptsächlich definiert type inference die umgekehrte Richtung, in der
sich der Typ der linken Seite einer Variablendeklaration aus dem Typ der
rechten Seite ergibt. Also
let x = 1u8;
eine 8-Bit Integer-Variable ohne Vorzeichen definiert, in Langform
let x: u8 = 1u8;
Das gibt es analog auch in neuerem C++:
auto y = 1u;
statt
unsigned y = 1;
Für nicht näher per Suffix spezifizierte lexikalische Konstanten kann
sich das wie hier im Thread thematisiert in Rust umkehren, weil sich bei
let x: u8 = 1;
aus der linken Seite der Typ ergibt, der die Zahl 1 als u8 vorgibt. In
let x = 1;
ist allerdings keine der beiden Seiten eindeutig typisiert, weshalb die
1 zu einer 32-Bit Integer und x damit zur i32 Variable wird.
In C müssen Compiler ein gewisses Mass an Toleranz gegenüber unpassenden
Typen von Konstanten entwickeln, um Programmierer nicht in nutzlosen
Warnungen zu ersäufen. In Rust ergibt sich das entweder aus dem Kontext,
wie gezeigt, oder läuft auf einen Fehler, wenn unpassend. Bei einer
neuen Sprache geht das, bei einer alten wie C eher nicht.
C muss aus historischen Gründen damit leben, dass sich
unsigned x = 1;
als links u32 und rechts i32 darstellen kann. Und das nicht nur bei
einer Konstanten rechts von Compiler oft grusslos akzeptiert wird, wie
in
... int x; ...
unsigned y = x;
weil Millionen von Programmierern das halt so machten. In Rust hat man
aus den Fehlern von C gelernt, und kann sie vermeiden, ohne Rücksicht
auf historischen Ballast nehmen zu müssen.
PS: Ich bitte um Korrektur, wenns falsch ist. Ich bin Rust erst gerade
eben näher begegnet, aber so ergibt sich das aus der Referenz.
(prx) A. K. schrieb:> Hauptsächlich definiert type inference die umgekehrte Richtung
"Hauptsächlich" finde ich ist hier nicht richtig.
Die Richtung ergibt sich aus der Tatsache, welche Seite nicht
(vollständig) typdefiniert ist.
Und das ist auch nur die halbe Wahrheit, denn der Typ kann sich auch
erst aus der weiteren Verwendung der Variablen ergeben (z.B. wenn sie
von der Funktion zurückgegeben wird oder wenn sie irgendwo übergeben
wird).
In der Regel gibt man gar keine Basistypen vor, außer an Schnittstellen
(Funktionen). Daraus ergeben sich dann alle anderen Typen.
Manchmal kann das natürlich verwirrend sein. Dann ist es dem
Programmierer freigestellt doch Typen zu definieren. Das hat auch den
Vorteil, dass der Compiler es dann prüft und ggf. einen Fehler ausgibt,
wenn der Typ der weiteren Verwendung widerspricht.
Und ganz selten kann der Compiler den Typ auch gar nicht automatisch
erkennen. Dann wird der Entwickler zu ebenjenem gezwungen.
In Großen und Ganzen ist die Type Inference in Rust aber sehr viel
eindeutiger für den Programmierer nachverfolgbar und zu verstehen, als
z.B. in C++ mit auto. Der tatsächliche Typ findet sich zu 99% "räumlich"
ganz in der Nähe. Und wenn nicht: Wie gesagt; dem Programmierer steht es
frei Typen zu deklarieren.
MaWin schrieb:> Kein implizites casting
Würde ich eher als Typkonvertierung bezeichnen, nicht als implizites
casting. Das Problem an (expliziten) type casts ist die brachiale
Gewalt, mit der sie irgendwie alles passend machen, während implizite
Typkonvertierung sanfter vorgeht und die Chance erhält, den
Programmierer auf Irrtümer hinzuweisen.
(prx) A. K. schrieb:> implizite> Typkonvertierung sanfter vorgeht und die Chance erhält, den> Programmierer auf Irrtümer hinzuweisen.
Was soll denn daran "sanft" sein?
Eine Konvertierung bleibt eine Konvertierung.
Der Typ ändert sich.
Wenn die Konvertierung implizit ist, dann besteht immer die Gefahr, dass
der Programmierer das so nicht gewollt hat. Und deshalb verbietet Rust
sie (und auch um Type Inference zu vereinfachen) nahezu vollständig.
Das ist dann der ultimative Hinweis an den Programmierer, weil das
Programm nicht mehr baut.
MaWin schrieb:> Was soll denn daran "sanft" sein?
Ein type cast sagt dem Compiler, dass er auch den grössten Mist
kommentarlos hinnehmen muss. Weshalb ich den Begriff "impliziter cast"
für widersprüchlich halte, und einen anderen Begriff favorisiere.
> Und deshalb verbietet Rust> sie (und auch um Type Inference zu vereinfachen) nahezu vollständig.
Und das ist völlig richtig so. Ich kritisiere Rust nicht, im Gegenteil.
(prx) A. K. schrieb:> Bei einfachen Ausdrücken wäre das zwar nicht immer effizient, aber noch> halbwegs übersichtlich. Das ändert sich in komplexeren Ausdrücken,> besonders bei Präprozessor-Makros wie> #define P(x,y) (x >> y)> Da es sich dabei um reine Textersetzung handelt, würde die Berechnung> innerhalb der Definition von P nicht mehr nur abhängig von den Typen von> x und y, sondern auch vom Kontext, in dem P verwendet wird. Also welche> Breite als Ergebnis von P erwartet wird.
Spannend wird das vor allem z.B. bei einem
1
#define P(x, y) ((x * 100) / y)
2
3
uint8_tvar1=P(10,50);
4
uint16_tvar2=P(10,50);
Das Ergebnis wäre hier 20, aber nur var2 würde auch diesen Wert
bekommen, denn die Berechnung für var1 würde überlaufen, da das
Zwischenergebnis von x * 100 nicht in 8 Bit passt.
Jörg W. schrieb:> Schlaumaier schrieb:>> Aber ich bin noch einer der 8.3 Generation.>> Geringfügig besser als die 6-Zeichen-FORTRAN-Generation. ;-)
Das war ja auch in C mal so. Es hat schon seinen Grund, weshalb die
Funktionsnamen der C89-Standardbibliothek alle nicht länger als 6
Zeichen sind. printf, malloc, strcpy u.s.w.
(prx) A. K. schrieb:> MaWin schrieb:>> Kein implizites casting>> Würde ich eher als Typkonvertierung bezeichnen, nicht als implizites> casting.
Das wäre dann auch richtig. Implizite Casts gibt es nicht. Eine
Umwandlung eines Typs in einen anderen ist in C eine Konvertierung, und
ein Cast ist das, was man hinschreiben muss, wenn man explizit eine
Konvertierung auslösen will.
> Das Problem an (expliziten) type casts ist die brachiale Gewalt, mit der> sie irgendwie alles passend machen, während implizite Typkonvertierung> sanfter vorgeht und die Chance erhält, den Programmierer auf Irrtümer> hinzuweisen.
Das liegt aber auch daran, das der C-Cast ein Vorschlaghammer ist, der
alles in die Wand haut, egal ob Nagel oder nicht. tatsächlich macht man
aber heute in Programmiersprachen oft weniger implizite Konveriterungen
als in C, da so sonst ggf. auch zu Blödsinn führen, aber ohne dass man
darauf überhaupt hingewiesen wird. Einen Cast muss man wenigstens selbst
ausdrücklich hinschreiben.
Rolf M. schrieb:> Das liegt aber auch daran, das der C-Cast ein Vorschlaghammer ist, der> alles in die Wand haut, egal ob Nagel oder nicht.
Ich hatte vor Jahren mal Microsoft .Net Code gesehen (nicht meine
Branche), der mit massenhaft type casts übersät war. Schaurig.
Rolf M. schrieb:> Das Ergebnis wäre hier 20, aber nur var2 würde auch diesen Wert> bekommen, denn die Berechnung für var1 würde überlaufen, da das> Zwischenergebnis von x * 100 nicht in 8 Bit passt.
Richtig. Die "Lösung" von C, jeden Ausdruck für sich zu typisieren, ist
aber nur unwesentlich sicherer.
Besser ist da einen Compilerfehler zu werfen
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=19e8239301dbdfb134f4f32340a6a96b
oder den Nutzer zu zwingen generics (templates) zu verwenden, wenn er
generischen Code schreibt.
Rolf M. schrieb:> Das war ja auch in C mal so. Es hat schon seinen Grund, weshalb die> Funktionsnamen der C89-Standardbibliothek alle nicht länger als 6> Zeichen sind. printf, malloc, strcpy u.s.w.
Sparsamkeit: 3 Zeichen per RADIX50 in 16 Bits, oder als 6x 6 Bit für die
damals noch gängige 36-Bit-Hardware, ergeben einen externen Namen. Viel
effizienter als normale Strings, egal ob mit Count vorne oder \0 hinten.
Aus einem ähnlichen Grund hatte das Wirth'sche Ur-Pascal der CDC 6600
einen implizit definierten String-Typ - die 10 6-Bit Zeichen des packed
array passten exakt in ein Maschinenwort.
MaWin schrieb:> Richtig.
Warum ist das richtig?
Rolf M. schrieb:> #define P(x, y) ((x * 100) / y)> uint8_t var1 = P(10, 50);> uint16_t var2 = P(10, 50);
Wo ist hier der Überlauf? Verstehe ich nicht.
mehr Bretto von Nutto mit der Grundinzidenz schrieb:> Wo ist hier der Überlauf? Verstehe ich nicht.
Wenn ((10 * 100) / 50) mit 8 Bits gerechnet würde, weil das Ergebnis nur
in 8 Bits verlangt wird. So ergäbe sich das, wenn die Typisierung der
Rechnung im Parser-Baum von oben nach unten durchgedrückt würde, statt
sich von unten nach oben zu entwickeln.
Schlaumaier schrieb:> Ja aber ich habe noch NIE eine Variable/Bezeichner mit einen> Sonderzeichen benannt. Die einzige Ausnahme ist der Unterstrich.Und das> gilt nicht nur für Programmcode sondern auch für Tabellen etc.
Mache ich auch so. Und deshalb finde ich es ja so gruselig, deutsche
Bezeichner zu verwenden, wenn man nicht alle dafür im Zweifel
notwendigen Zeichen zur Verfügung hat. ;-)
Nachdenklicher schrieb:> Und deshalb finde ich es ja so gruselig, deutsche> Bezeichner zu verwenden
hihi. Was glaubst du was ich manchmal an einer pissigen Excelformel
sitze, weil ich nicht mehr weiß wie die INSTR-Funktion o.ä. auf Deutsch
heißt. ;)
Wobei die LEN-Funktion die Krönung ist. =Länge(a1) "die Spinnen die
Redmonder"
Schlaumaier schrieb:> hihi. Was glaubst du was ich manchmal an einer pissigen Excelformel> sitze, weil ich nicht mehr weiß wie die INSTR-Funktion o.ä. auf Deutsch> heißt. ;)
Uah.. eine Programmiersprache, bei der die Funktionsnamen mit der
Sprache der Benutzeroberfläche zusammen übersetzt werden. Das ist
wirklich nur was für die ganz harten. :'-D