Hallo, warum schreibt man eigentlich hinter dem wert von einer unsigned variablen nochmal ein u? z.B. uint8_t 0x0Au; uint8_t 8u;
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
dummschwaetzer schrieb: > guter Style ja vielleicht, aber wofür steht das u? der typ steht ja schon davor.
Kurz gesagt: legt fest, welchen Datentyp der Compiler für den (oder das?) Literal annimmt. 0x0A könnte ein int werden, 0x0AU wird sicher ein usigned int. https://stackoverflow.com/questions/23858417/using-constants-and-their-associated-modifiers-using-gcc
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.
:
Bearbeitet durch User
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).
:
Bearbeitet durch Moderator
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 | int x; |
2 | unsigned y; |
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.
Beitrag #6671445 wurde von einem Moderator gelöscht.
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_t x = 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?
1 | $ cat hw.c |
2 | #include <stdio.h> |
3 | |
4 | int |
5 | main(void) |
6 | { |
7 | const char *hälloworld = "Hello, world!"; |
8 | puts(hälloworld); |
9 | return 0; |
10 | } |
11 | $ clang -O -o hw hw.c |
12 | $ ./hw |
13 | Hello, world! |
Oder was genau wolltest du damit ausdrücken?
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.
:
Bearbeitet durch User
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.
Schlaumaier schrieb: > Aber ich bin noch einer der 8.3 Generation. Geringfügig besser als die 6-Zeichen-FORTRAN-Generation. ;-)
1 | km1 = k - 1 |
2 | absakk = cabs1(a(k,k)) |
3 | imax = icamax(k-1,a(1,k),1) |
4 | colmax = cabs1(a(imax,k)) |
5 | if (absakk .lt. alpha*colmax) go to 30 |
6 | kstep = 1 |
7 | swap = .false. |
8 | go to 90 |
9 | 30 continue |
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.)
:
Bearbeitet durch Moderator
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.
:
Bearbeitet durch User
(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.
:
Bearbeitet durch User
(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.
:
Bearbeitet durch User
(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_t var1 = P(10, 50); |
4 | uint16_t var2 = 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.
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.