Forum: PC-Programmierung warum schreibt man hinter dem wert von einer unsigned variablen nochmal ein u


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Lars (Gast)


Lesenswert?

Hallo,
warum schreibt man eigentlich hinter dem wert von einer unsigned 
variablen nochmal ein u?

z.B.
uint8_t 0x0Au;
uint8_t 8u;

von dummschwaetzer (Gast)


Lesenswert?

guter Style

von Achim M. (minifloat)


Lesenswert?

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

von Lars (Gast)


Lesenswert?

dummschwaetzer schrieb:
> guter Style

ja vielleicht, aber wofür steht das u?
der typ steht ja schon davor.

von tralala (Gast)


Lesenswert?

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

von Oliver S. (oliverso)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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

von Johannes O. (jojo_2)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Schlaumaier (Gast)


Lesenswert?

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.

von Johannes O. (jojo_2)


Lesenswert?

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.

von Schlaumaier (Gast)


Lesenswert?

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.

von oerks (Gast)


Lesenswert?

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.

von A. S. (achs)


Lesenswert?

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)

von Mladen G. (mgira)


Lesenswert?

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.

von Schlaumaier (Gast)


Lesenswert?

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

von Roland F. (rhf)


Lesenswert?

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

von Mladen G. (mgira)


Lesenswert?

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

von A. S. (achs)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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
von Roland F. (rhf)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.
von A. S. (achs)


Lesenswert?

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.

von Schlaumaier (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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

von Nachdenklicher (Gast)


Lesenswert?

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

von P. S. (namnyef)


Lesenswert?


von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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?

von Roland F. (rhf)


Lesenswert?

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

von Roland F. (rhf)


Lesenswert?

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.

von Nachdenklicher (Gast)


Lesenswert?

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

von MaWin (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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
von Nachdenklicher (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Nachdenklicher (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Schlaumaier (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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

von Schlaumaier (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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
von MaWin (Gast)


Lesenswert?

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.

von Percy N. (vox_bovi)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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
von MaWin (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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
von MaWin (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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
von Rolf M. (rmagnus)


Lesenswert?

(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
von (prx) A. K. (prx)


Lesenswert?

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.

von MaWin (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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
von mehr Bretto von Nutto mit der Grundinzidenz (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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
von Nachdenklicher (Gast)


Lesenswert?

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

von Schlaumaier (Gast)


Lesenswert?

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"

von Nachdenklicher (Gast)


Lesenswert?

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.