Standardkost würde ich jetzt nicht sagen.
Ich würde eher jeden verhauen, der solch ein Konstrukt tatsächlich
benutzen möchte :)
Das fällt in die Rubrik kann man machen, sollte man aber nicht.
Hi,
wenn ich es richtig verstehe, dann wird die Variable i jetzt schon vor
dem Vergleich dekrementiert, anstatt erst am Schleifenwendepunkt. Sollte
man aber bedenken, wenn man i noch im Schleifenkörper braucht.
Ich persönlich halte von dieser Verkrypterei nicht viel, insbesondere C
bringt das immer wieder in Verruf.
Viele Grüße,
Servo
Servo schrieb:> wenn ich es richtig verstehe, dann wird die Variable i jetzt schon vor> dem Vergleich dekrementiert,
Nein. Das ist ganz normales Postdekrement.
> anstatt erst am Schleifenwendepunkt.
Was soll das sein?
leo
> Standardkost würde ich jetzt nicht sagen.
Simple assignment, postfix decrement und relational operator gibts so
seit mindestens 30 Jahren (ich vermute mal dass er auf diese 3
Operatoren raus will). Kaum ein Programm kommt ohne die aus,
0815-Standardkost. Wer die nicht (er)kennt, kennt nicht wirklich was.
Nix für ungut.
Vielleicht sollte man wirklich C++ nutzen.
Es gibt da nämlich auch rückwärts laufende Iteratoren, die das Ganze
mittels std::for_each() ausdrückbar machen. (falls "rückwärts" das Ziel
ist)
Edit: seh gerade, StackOverflow meint das auch ;-)
Das ursprüngliche Problem für diese rhetorische Frage war, ein Array
rückwärts zu durchlaufen.
Wie durläuft man ein Array rückwärts, wenn man das Programmieren gelernt
hat?, so dass man:
- unsgined int verwenden kann und
- mit den Arraydimensionen arbeiten kann, ohne +/- 1?
C. P. P. Lovejoy schrieb:> Das ursprüngliche Problem für diese rhetorische Frage war, ein Array> rückwärts zu durchlaufen.>> Wie durläuft man ein Array rückwärts, wenn man das Programmieren gelernt> hat?, so dass man:>> - unsgined int verwenden kann und> - mit den Arraydimensionen arbeiten kann, ohne +/- 1?
Indem man von rbegin() nach rend() iteriert.
C. P. P. Lovejoy schrieb:> Carl D. schrieb:>> Indem man von rbegin() nach rend() iteriert.>> Wie bekommt man dann den Index?
Vor dem Rückwärtsiterieren sollte man ansatzweise das Vorwärtsiterieren
verstehen. Man braucht da keinen Index, der Iterator ist quasi ein
Zeiger auf das vector/array/...-Element.
Z.B. int-Vector rückwärts ausgeben:
Carl D. schrieb:> Man braucht da keinen Index, der Iterator ist quasi ein> Zeiger auf das vector/array/...-Element.
Was ist da der Unterschied zu einem Pointer-In(De-)krement? Mehr Syntax?
leo
leo schrieb:>> wenn ich es richtig verstehe, dann wird die Variable i jetzt schon vor>> dem Vergleich dekrementiert,>> Nein. Das ist ganz normales Postdekrement.
Ja hast recht. Insofern macht das noch weniger Sinn. Ich würde sowas
auch niemals so hinschreiben, da stolpert man doch drüber. Ein einzelnes
i--; oder i++; ist doch viel eindeutiger.
>>> anstatt erst am Schleifenwendepunkt.>> Was soll das sein?
Ach komm. Ich weiß wirklich nicht, ob es da ein anderes Wort für gibt,
aber in diesem Kontext kann ja man sich eindeutig denken was gemeint
ist. Die for-Schleife ist vorprüfend, und das letzte Statement in der
for-Klammer wird erst nach der Ausführung des Rumpfes abgearbeitet. An
dieser Stelle "wendet" dann die Schleife. Daher meine kreative
Wortschöpfung" :-)
Viele Grüße,
Servo
leo schrieb:> Servo schrieb:>> wenn ich es richtig verstehe, dann wird die Variable i jetzt schon vor>> dem Vergleich dekrementiert,>> Nein. Das ist ganz normales Postdekrement.
In der hier vorgestellten Syntax wird der Check (i>0) und der Dekrement
(i--) vor dem Ausführen des Schleifenkörpers gemacht, wenn es
1
for(..;i>0;i--)
wäre, dann würde der Dekrement nach dem Ausführen des Schleifenkörpers
gemacht. Ersteres iteriert über [stdv.size() -1; 0], letzteres über
[stdv.size(); 1].
Ich würde diese Form aber auch nicht nutzen. Da muss man drei mal
schauen bis man kappiert was da passiert.
leo schrieb:> Carl D. schrieb:>> Man braucht da keinen Index, der Iterator ist quasi ein>> Zeiger auf das vector/array/...-Element.>> Was ist da der Unterschied zu einem Pointer-In(De-)krement? Mehr Syntax?>> leo
Z.B. daß v auch ein anderer Container mit Rückwärts-Iterator sein darf,
ohne daß man einen (überladenen) [] Operator bräuchte.
Ein Iterator kann ein (Smart-)Pointer sein, oder aber auch was ganz
anderes.
C. P. P. Lovejoy schrieb:> Carl D. schrieb:>> C++11 vorausgesetzt.>> Danke fürs Beispiel. Schön, dass C schon immer eine Lösung hat, und C++> im Zeitgeist frolockt.
In C++ kann v aber auch ein Objekt sein, das aus stdin liest und dessen
Iterator über den * Operator das aktuelle Zeichen liefert, via ++
Operator das nächste Zeichen liest und dieses via != Operator mit '\n'
vergleicht. Dann iteriert man mit dem gezeigten Code über die Zeichen
einer Zeile. Da tut sich der Index schwer.
Carl D. schrieb:> C. P. P. Lovejoy schrieb:>> Carl D. schrieb:>>> C++11 vorausgesetzt.>>>> Danke fürs Beispiel. Schön, dass C schon immer eine Lösung hat, und C++>> im Zeitgeist frolockt.>> In C++ kann v aber auch ein Objekt sein, das aus stdin liest und dessen> Iterator über den * Operator das aktuelle Zeichen liefert, via ++> Operator das nächste Zeichen liest und dieses via != Operator mit '\n'> vergleicht. Dann iteriert man mit dem gezeigten Code über die Zeichen> einer Zeile. Da tut sich der Index schwer.
Ein reverse-Iterator aber auch... :)
Jeder Zeiger ist ein Iterator, aber nicht jeder Iterator ist ein Zeiger.
Ein Iterator ist ein abstraktes Konzept (nein, ich meine nicht concepts
und requirements, denn das Iterator-Konzept ist Uralt in C++). Dieses
Konzept verlangt eine bestimmte Operationenmenge. Jeder Dytentyp, der
diese Typanforderungen erfüllt, ist eine Iterator. Und kann auch für die
Algorithmen der stdlib verwendet werden.
übrigens haben Prozessoren mit einer Loop Einheit im Core meist das
Problem den Schleifenzähler/Iterator nicht in der Load/Store Einheit
gleichzeitig verwenden zu können.
Wenn man also den Iterator auch als Array Index verwendet wird kann die
"Zero Overhead Loop Unit" nicht verwendet werden => Schleife benötigt
mehr Takte.
Eine Zweite Variable die auch problemlos in die andere Richtung laufen
kann ist effizienter.
Die HW-Loop Counter sind meist übrigens Down-Counter.
Servo schrieb:> wenn ich es richtig verstehe, dann wird die Variable i jetzt schon vor> dem Vergleich dekrementiert, anstatt erst am Schleifenwendepunkt. Sollte> man aber bedenken, wenn man i noch im Schleifenkörper braucht.
Wenn ich c richtig verstanden habe, dann wird der dritte Parameter im
"Schleifenkopf" am Ende des "Schleifenkörpers" durchgeführt.
Zur Vollständigkeit :
Der erste Parameter im "Schleifenkopf" wird einmal am Beginn der
Schleifeninitalisierung, der Zweite vor Eintritt im Schleifenkörper
durchgeführt.
Die Eingangs gepostete Schleife nutze ich eigentlich sehr gerne. Meiner
Meinung nach beugt das auch versehentliche Endlosschleifen vor in denen
unsigned < 0 verglichen wird.
Guest schrieb:> Ach komm, der String-Klammer-Operator ist schöner=>
Bernd K. schrieb:> Der Parser oder Tokenizer oder meinetwegen auch die ganze Grammatik ist> krank wenn das erlaubt ist ohne einen Syntaxfehler auszuspucken.
Dabei ist es doch ganz einfach. In C sind Whitespaces und Zeilenumbrüche
kein Syntaxelement. Sie können also weggelassen werden, solange sich der
Ausdruck noch eindeutig parsen läßt.
Nur der Mensch braucht sie zur besseren Lesbarkeit. Also ist auch er in
der Verantwortung, sie sinnvoll zu setzen.
Vincent H. schrieb:> Guest schrieb:>> Ach komm, der String-Klammer-Operator ist schöner=>>> int i = 0;>> char a = i["abcde"];>>> Das kannte ich auch nicht...
Subscript-Operator
Es ist definiert:
nicht"Gast" schrieb:> Standardkost würde ich jetzt nicht sagen.>> Ich würde eher jeden verhauen, der solch ein Konstrukt tatsächlich> benutzen möchte :)
Jau! Und Fahrrad nur mit Helm besteigen - und an die Strasse bei jeder
50cm hohen Böschung eine doppelte Leitplanke und nur noch in Warnweste
und mit Schutzbrille rumrennen!!!
LoL
C. P. P. Lovejoy schrieb:> for (unsigned int i = stdv.size(); i --> 0; )
Ich verstehe nicht genau, was hier neu sein soll?
Habe nciht alles gelesen. Das sieht mir aber nach altem Hut aus. Kein
neuer Operator.
i-->0 ist lediglich (i--)>0
Und das ist:
* Dekrementiere i
* liefere Vergleich, ob i (vor dem dekrement) größer als 0
Stichwort: Operator Precedence. Soltle man grob kennen von den Sprachen,
die man verwendet.
und dann eben vor jedem Schleifendurchlauf durchgeführt (Zweites
Statement in den Klammern der for-Schleife) und der Einsprung in den
Schleifenkörper findet nur statt, wenn der Ausdruck != 0 liefert.
Ich stelle leider immer wieder fest, dass die Grundfesten von C,
speziell eine for-Schleife, bei den meisten nicht richtig gelehrt
wurden.
for (a; b; c) d;
1) Als erstes wird das Statement "a" ausgeführt.
2) Dann wird zur Prüfung der Einsprungbedingnung übergegangen. Dazu wird
"b" ausgeführt. Der Rückgabewert von was auch immer da steht,
entscheidet, ob der Schleifenkörper "d" ausgeführt wird.
3) Am Ende wird Statement "c" ausgeführt.
4) => Weiter bei Punkt 2)
Viele scheinen darauf festgenagelt zu sein, dass
1) a nur eine Initialisierung,
2) b nur eine Bedingung / Vergleich
3) und c nur ein Inkrement/Dekrement sein kann.
Da kann jedoch jedes beliebige Statement stehen.
Dazu ein kleines Beispiel:
Die Elemente einer verkettete Liste 'list_head' mit der Struktur
1
structlist_item{
2
void*data;
3
structlist_item*next;
4
}
können bspw. so gezählt werden (ja ich weiß, verkettete Listen sind
langsam und skalieren schlecht):
M. H. schrieb:> for (a; b; c) d;
Zu beachten ist aber, daß mit continue zu c gesprungen wird.
Bei do/while und while springt continue dagegen zum Vergleich.
Bernd K. schrieb:> Der Parser oder Tokenizer oder meinetwegen auch die ganze Grammatik ist> krank wenn das erlaubt ist ohne einen Syntaxfehler auszuspucken.
Interpunktion ist jetzt auch nicht Deine Stärke.
M. H. schrieb:> Viele scheinen darauf festgenagelt zu sein, dass> 1) a nur eine Initialisierung,> 2) b nur eine Bedingung / Vergleich> 3) und c nur ein Inkrement/Dekrement sein kann.M. H. schrieb:> Da kann jedoch jedes beliebige Statement stehen.
Bei a) stimmt das so leider nicht.
Hier sind nur expression-statements und simple-declarations erlaubt.
M. H. schrieb:> for (len = 0, iter = list_head; iter; iter = iter->next, len++);
Hier hast Du also für a) den Komma-Operator eingesetzt
(expression-stmt).
C. P. P. Lovejoy schrieb:> C/C++: Kennt ihr diesen "Operator" schon?
Ein kurzes "Häh?" hat mit dieses --> schon entlockt :)
Aber auch wenn das korrekt ist, würde ich dennoch die Schreibweise
1
for(unsignedinti=stdv.size();i-->0;)
bevorzugen, um anderen den "Häh?"-Effekt zu ersparen. Da ich unäre
Operatoren immer direkt (ohne Leerzeichen) an den Operanden hefte und
binäre Operatoren meist beidseitig mit Leerzeichen von den Operanden
trenne, ergibt sich diese Schreibweise bei mir ganz von selber.
Bernd K. schrieb:> Der Parser oder Tokenizer oder meinetwegen auch die ganze Grammatik ist> krank wenn das erlaubt ist ohne einen Syntaxfehler auszuspucken.
In den meisten Programmiersprachen können mehrere Operatoren direkt
hintereinander geschrieben werden, da sie neben ihrer eigentlichen
Funktion auch als Delimiter fungieren. So ist bspw.
1
a <-- b
in C, C++, Java, Python, Ruby, Pascal u.v.m. ein legaler Ausdruck, der
in C, C++ und Java äquivalent zu
1
a<(--b)
und in Python, Ruby und Pascal (wo es kein -- gibt) äquivalent zu
1
a<(-(-b))
ist.
So gesehen ist jede der genannten Sprachen "krank" ;-)
Eine der wenigen "gesunden" Ausnahmen stellt Haskell dar: Dort wird das
<-- tatsächlich als ein einzelner Operator geparst, der aber – da nicht
in der Standardbibliothek enthalten – selbst definiert werden muss. Soll
das Verhalten von Python, Ruby und Pascal nachgebildet werden, lautet
diese Definition ganz einfach
Yalu X. schrieb:> Aber auch wenn das korrekt ist, würde ich dennoch die Schreibweise>> for (unsigned int i = stdv.size(); i-- > 0; )>> bevorzugen
Als Ausdruck künstlerischer Potenz vielleicht.
Wenn ich mit stdv.size-1 in die Schleife gehen will und auch die 0 haben
will, dann sollte es auch so schreiben, falls ein Programmierer
(Nachfolger) und nicht-Künstler das mal lesen muss. Also:
1
/* langweilige version */
2
for(unsignedinti=stdv.size()-1;i>=0;i--)
Ja, ist ein bisschen länger. Frag einfach mal 5 Leute: Die Funktion gibt
10 zurück, mit welchen werten i wird die Schleife durchlaufen? und
schaue, wo sie mehr straucheln.
A. S. schrieb:> Yalu X. schrieb:>> Aber auch wenn das korrekt ist, würde ich dennoch die Schreibweise>>>> for (unsigned int i = stdv.size(); i-- > 0; )>>>> bevorzugen>> Als Ausdruck künstlerischer Potenz vielleicht.> Wenn ich mit stdv.size-1 in die Schleife gehen will und auch die 0 haben> will, dann sollte es auch so schreiben, falls ein Programmierer> (Nachfolger) und nicht-Künstler das mal lesen muss. Also:>>
1
>/* langweilige version */
2
>for(unsignedinti=stdv.size()-1;i>=0;i--)
3
>
> Ja, ist ein bisschen länger. Frag einfach mal 5 Leute: Die Funktion gibt> 10 zurück, mit welchen werten i wird die Schleife durchlaufen? und> schaue, wo sie mehr straucheln.
Satire? :D
Falls nicht, hint:
A. S. schrieb:> Als Ausdruck künstlerischer Potenz vielleicht.> Wenn ich mit stdv.size-1 in die Schleife gehen will und auch die 0 haben> will, dann sollte es auch so schreiben, falls ein Programmierer> (Nachfolger) und nicht-Künstler das mal lesen muss. Also:> /* langweilige version */> for(unsigned int i = stdv.size()-1; i>=0; i--)
Bamm!!! Juhu, der Klassiker!
Walter K. schrieb:> Jau! Und Fahrrad nur mit Helm besteigen - und an die Strasse bei jeder> 50cm hohen Böschung eine doppelte Leitplanke und nur noch in Warnweste> und mit Schutzbrille rumrennen!!!
Du kannst das natürlich halten wie ein Dachdecker.
Einfache Tatsache ist aber, dass eine solche Schreibweise unüblich ist
und der geneigte Leser erst mal drüber fällt, was da jetzt wirklich
passiert.
Dazu gibts keine Perfomanceverbesserung gegenüber einer üblichen
Schreibweise. Ergo -> Schrott der nur Fehler verursacht.
Peter D. schrieb:> M. H. schrieb:>> for (a; b; c) d;>> Zu beachten ist aber, daß mit continue zu c gesprungen wird.> Bei do/while und while springt continue dagegen zum Vergleich.
Ist essentiell das gleiche bzw. sogar dasselbe Verhalten.
continue überspringt den Rest des Statementblocks "d". Bei einer
for-Schleife kommt dann eben "c" vor "b".
A. S. schrieb:> Ja, ist ein bisschen länger. Frag einfach mal 5 Leute: Die Funktion gibt> 10 zurück, mit welchen werten i wird die Schleife durchlaufen? und> schaue, wo sie mehr straucheln.
Die Antwort, die man hier lernt wäre, dass man das nicht sagen kann,
weil es implementation-defined ist. Und wenn im Body nicht irgendwas mit
Seiteneffekt steht sogar UB.
Heiko L. schrieb:> A. S. schrieb:>> Ja, ist ein bisschen länger. Frag einfach mal 5 Leute: Die Funktion gibt>> 10 zurück, mit welchen werten i wird die Schleife durchlaufen? und>> schaue, wo sie mehr straucheln.>> Die Antwort, die man hier lernt wäre, dass man das nicht sagen kann,> weil es implementation-defined ist. Und wenn im Body nicht irgendwas mit> Seiteneffekt steht sogar UB.
Wo ist da etwas implementation-defined?
mh schrieb:> Heiko L. schrieb:>> A. S. schrieb:>>> Ja, ist ein bisschen länger. Frag einfach mal 5 Leute: Die Funktion gibt>>> 10 zurück, mit welchen werten i wird die Schleife durchlaufen? und>>> schaue, wo sie mehr straucheln.>>>> Die Antwort, die man hier lernt wäre, dass man das nicht sagen kann,>> weil es implementation-defined ist. Und wenn im Body nicht irgendwas mit>> Seiteneffekt steht sogar UB.>> Wo ist da etwas implementation-defined?
"mit welchen Werten" - das hängt von der Breite des unsigned ints ab.
Implementation defined.
Heiko L. schrieb:> Die Antwort, die man hier lernt wäre, dass man das nicht sagen kann,> weil es implementation-defined ist.
Doch, kann man sagen: Alle Werte im Bereich 0 bis UINT_MAX.
Rolf M. schrieb:> Heiko L. schrieb:>> Die Antwort, die man hier lernt wäre, dass man das nicht sagen kann,>> weil es implementation-defined ist.>> Doch, kann man sagen: Alle Werte im Bereich 0 bis UINT_MAX.
Ach so... ich dachte, die Frage zielt auf eine Aufzählung...
Rolf M. schrieb:> Ich glaube, die Frage war sowieso ganz anders gedacht.
Klar. Da fragt man sich, wie lange es wohl dauert, bis der Fehler
auffällt.
<-- Hahahaha!
Zum Beispiel einem Build-Server.
Yalu X. schrieb:> Ein kurzes "Häh?" hat mit dieses --> schon entlockt :)
Insbesondere wenn man eine Code-Schriftart mit den passenden Ligaturen
verwendet ;) .
Eigentlich hatte ich ja gehofft, es geht um den operator<=>...
Dann sieht man das die Wirkungsweise nur darauf zielt das die for
Schleife um einmal weniger ausgeführt wird wie sonst üblich. Also ohne
das Zuweisungs minus ein.
Am Ende könnte auch das dastehen, je nachdem womit i initialisiert wird.
Ohne Zusammenhang kann man darüber nur spekulieren.
Veit D. schrieb:> also lesbarer wird es> for (unsigned int i = stdv.size()-1; i > 0; i--)> {> std::cout << stdv[i];> }
entspricht aber nicht dem Original!
h
Veit D. schrieb:> Am Ende könnte auch das dastehen, je nachdem womit i initialisiert wird.> Ohne Zusammenhang kann man darüber nur spekulieren.> for (unsigned int i = stdv.size(); i > 1; i--)> {> std::cout << stdv[i];> }
Und das ist total falsch!
Und auch in dem ursprünglichen Code ist ein subtiler Fehler drin.
So ist es richtig:
1
for(autoi{stdv.size()};i-->0;){
2
std::cout<<stdv[i];
3
}
Den Fehler bekommt man übrigens auch angezeigt wenn man korrekt
initialisieren und den falschen DT verwendet:
Veit D. schrieb:> ich habe das getestet, zeigt exakt das gleiche Verhalten.
Und Du meinst jetzt, ein(!) kleiner Test sei ein Beweis für die
Korrektheit?
Im übrigen entspricht das nicht der Version, die ein Problem hat. Was Du
jetzt gepostest hast, ist tatsächlich so korrekt.
Hallo,
du meinst den Unterschied zwischen signed und unsigned. Ja das habe ich
in weiser Voraussicht korrigiert. Denn unsigend > 0 ist immer wahr. Wäre
also sinnfrei.
Veit D. schrieb:> du meinst den Unterschied zwischen signed und unsigned.
Jein.
Auch da passieren beliebig viele Fehler, wenn signed und unsigned Typen
gemischt werden. Eigentlich ein sehr bekanntes Problem:
Schau Dir dies mal an, dann verstehst Du was ich meine:
Hallo,
du möchtest bestimmt mit int einen Überlauf und damit ein falsches
Ergebnis provozieren. Ich erhalte allerdings abgesehen von der Warnung
3x die Ausgabe 1073741824.
Veit D. schrieb:> du möchtest bestimmt mit int einen Überlauf und damit ein falsches> Ergebnis provozieren.
Genau, Du hast es ;-)
Veit D. schrieb:> Ich erhalte allerdings abgesehen von der Warnung> 3x die Ausgabe 1073741824.
Ist die erste Zeile so, wie ich sie geschrieben habe? Vermutlich hast Du
da schon den ersten Überlauf.
Für Größenangaben (Container-Größen, Elementanzahlen) sollte man immer
size_t verwenden oder eben automatische Typinferenz. Ab C++20 kann man
generell auch von den vorzeichenlosen Typen weg und verwendet c.ssize().
Hallo,
also sollte normalerweise der erste Wert falsch sein bzw. von den
anderen beiden abweichen?
Ich habe das in CodeBlocks 17.12 wie folgt ausprobiert, allerdings "nur"
mit gcc 7.1. Das ist laut Buch frisch installiert. Normalerweise
programmiere ich direkt für 8Bit Atmel µC und nicht am PC für den PC.
Hallo,
ich wollte die ausgebliebene int Provokation nochmal testen.
Auf meinem PC ist int 32 bit groß. Dadurch klappt das nicht.
Ändere ich int in int16_t erhalte ich
1073741824
0
1073741824
Hallo,
ich übersetze. Du wolltest den Wertebereichsüberlauf provozieren, sprich
bewusst herbeiführen. Was aus irgendwelchen Gründen nicht klappt.
"integer promotion".
Ich wollte dem Integer keinen Doktortitel verleihen.
Veit D. schrieb:> Ich habe das in CodeBlocks 17.12 wie folgt ausprobiert, allerdings "nur"> mit gcc 7.1
Auf was für einem System? Wie groß ist ein size_t?
Veit D. schrieb:> int l3{v1.size()}; // Hier kommt eine Warnung
Was kommt denn da für eine Warnung? Das müsste nen Fehler geben.
verursacht diesen Fehlermeldung
decltype evaluates to 'std::vector<char>::size_type {aka unsigned int}',
which is not a class or enumeration type|
und
1
intl3{v1.size()};// Hier kommt eine Warnung
bringt folgende Warnung
narrowing conversion of 'v1.std::vector<char>::size()' from
'std::vector<char>::size_type {aka unsigned int}' to 'int' inside { }
[-Wnarrowing]|
Aber darum ging es mir nicht.
Es ging um diese Zeile
1
intl1=v1.size();// Deine Variante
hier müßte doch auf Grund vom Wertebereichüberlauf ein falsches Ergebnis
erscheinen. Macht er nicht weil das Ergebnis in 32bit int passt. Bohre
ich den Wert auf erhalte ich überall 0, was auch nicht sein kann.
Wilhelm M. schrieb:> mh schrieb:>> Was kommt denn da für eine Warnung? Das müsste nen Fehler geben.>> Nein, kein Fehler. Sondern nur die "narrowing" Warnung.
Hmmm ist das nicht "list initialization"? Müsste dann nicht nen Fehler
sein? Hier ein Auszug aus
https://en.cppreference.com/w/cpp/language/list_initialization (hab grad
keine Lust auf Standard lesen)
1
Otherwise (if T is not a class type), if the braced-init-list has only one element and either T isn't a reference type or is a reference type whose referenced type is same as or is a base class of the type of the element, T is direct-initialized (in direct-list-initialization) or copy-initialized (in copy-list-initialization), except that narrowing conversions are not allowed.
clang sagt, dass es nen error ist.
1
error: non-constant-expression cannot be narrowed from type 'std::vector::size_type' (aka 'unsigned long') to 'int' in initializer list [-Wc++11-narrowing]
Hier läuft es wie zu erwarten ist über. 1024*1024*1024 gibt 2^30. Das
passt in 32 Bit. Wenn man das mit 1024 multipliziert, bekommst du 2^40.
Davon bleiben nur die unteren 32 Bit übrig, und die sind alle 0. Wenn
man das dann mit 5 multipliziert, ist es immer noch 0. Es wird also ein
vector mit 0 Elementen erzeugt. Dass dann für size() 0 zurückkommt, ist
also zu erwarten.
mh schrieb:> Hmmm ist das nicht "list initialization"?
Nein, es ist brace-initialization, in diesem Fall als
direct-scalar-initialization. Für Aggregate wäre es dann
list-initialization.
Dafür hat sich der Begriff "uniform initialization syntax" gebildet.
Veit D. schrieb:> Ich glaube wir haben jetzt genug getestet.> Problem war und ist klar dargelegt wurden.
Denke ich auch, und es freut mich, wenn Du den Unterschied verstanden
hast.
Wilhelm M. schrieb:> mh schrieb:>> Hmmm ist das nicht "list initialization"?>> Nein, es ist brace-initialization, in diesem Fall als> direct-scalar-initialization. Für Aggregate wäre es dann> list-initialization.>> Dafür hat sich der Begriff "uniform initialization syntax" gebildet.
Soweit ich das überblicke handelt es sich um "direct
list-initialization". direct-initialization nach
http://eel.is/c++draft/dcl.init#16.1 und list-initialized nach
http://eel.is/c++draft/dcl.init#17.1.
Und bei list-initialized trifft http://eel.is/c++draft/dcl.init#list-3.9
zu. Dort gibt es dann auch ein Beispiel:
direct-initialization mit einem single brace enclosed initializer. Dies
ist
eine Spezialform der list-initialization
https://en.cppreference.com/w/cpp/language/list_initialization
mit einer Liste mit einem Wert.
Die brace-initialization von Scalaren oder Aggregaten wird dann auch
ugs. als "uniform initialization syntax" bezeichnet. Den Ausdruck finde
ich sehr gut, denn diese Syntax ist wirklich universell, und tut das,
was man erwartet, und warnt bzw. lehnt ein narrowing an/ab.
Wilhelm M. schrieb:> direct-initialization mit einem single brace enclosed initializer. Dies> ist> eine Spezialform der list-initialization> https://en.cppreference.com/w/cpp/language/list_initialization
Das ist genau das was ich geschriben hab. Und wenn man aus den
beschriebenen Fällen, den einen Fall heraussucht, der hier zutrifft,
findet man:
1
T object { arg1, arg2, ... }; (1)
2
3
List initialization is performed in the following situations:
4
direct-list-initialization (both explicit and non-explicit constructors are considered)
5
1) initialization of a named variable with a braced-init-list (that is, a
6
possibly empty brace-enclosed list of expressions or nested braced-init-lists)
7
8
Explanation
9
The effects of list initialization of an object of type T are:
10
Otherwise (if T is not a class type), if the braced-init-list has only one
11
element and either T isn't a reference type or is a reference type whose
12
referenced type is same as or is a base class of the type of the element, T
13
is direct-initialized (in direct-list-initialization) or copy-initialized
14
(in copy-list-initialization), except that narrowing conversions are not
mh schrieb:> Das ist genau das was ich geschriben hab.
Sehr gut, da sind wir uns einig. Und Du hattest die bessere,
standard-konforme Wortwahl!
mh schrieb:> except that narrowing conversions are not> allowed.
Ich denke, dass ist nicht normativ. Sprich, der gcc darf ein mögliches
narrowing warnen, und muss ein definitives narrowing mit Wertänderung
als Fehler behandeln. Offensichtlich sieht das der clang anders (was mir
besser gefällt).
Das sollte man (Du?) mal auf der isocpp ML klären.
Wilhelm M. schrieb:> Sprich, der gcc darf ein mögliches> narrowing warnen, und muss ein definitives narrowing mit Wertänderung> als Fehler behandeln.
Ob, der tatsächliche Wert in den Typ passt, ist egal. In beiden Fällen
ist es laut Standard ill-formed
http://eel.is/c++draft/dcl.init#list-7.4. Er muss also in beiden fällen
nur warnen, darf aber einen Fehler erzeugen.
> Das sollte man (Du?) mal auf der isocpp ML klären.
Das Probem ist eher der gcc. Und ich vermute, die haben das mit Absicht
gemacht.
Rolf M. schrieb:> Veit D. schrieb:>> Bohre ich den Wert auf erhalte ich überall 0, was auch nicht sein kann.>> Warum nicht?
Hallo Rolf,
dich hatte ich komplett übersehen. Sorry.
Okay. Warum habe ich was anderes erwartet?
Weil mir nachwievor die Differenz als falsches Ergebnis fehlt.
1
uint32_tvar1=(1024UL*1024UL*1024UL*5);
2
std::cout<<var1<<'\n';
3
4
uint16_tvar2=1024UL*1024UL*1024UL*5;
5
std::cout<<var2<<'\n';
Ausgabe:
1073741824
0
Ich rechne nochmal.
1
1024 * 1024 * 1024 * 5 = 5.368.709.120
Wertebereich von uint32 ist 0 ... 4.294.967.296
Die Differenz ist 1073741824. Das ist der Rest vom Überlauf. Wie
erwartet.
Wertebereich von uint16 ist 0 ... 65.536
Der Wert 65.536 passt 81920 mal rein. Rest 0.
:-) :-) :-)
Alles klar, habe micht selbst geschlagen.
Ich hatte nicht erwartet das es beim letzen Überlauf ohne Rest aufgeht.
Jetzt bin ich glücklich mit mir selbst. :-)