mikrocontroller.net

Forum: Compiler & IDEs C++ andere Bedeutung der Mehrfachzuweisung


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.
Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In C++ sieht man ja oft solche Mehrfachzuweisungen:
counter = flankenerkennung = entprellen = taster;
Unter C ist die Bedeutung eindeutig, alle Variablen werden auf den 
gleichen Wert gesetzt.
Unter C++ ist die Bedeutung aber eine völlig andere. Wo kann man 
nachlesen, was das bedeutet?

Autor: DPA (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> In C++ sieht man ja oft solche Mehrfachzuweisungen:counter =
> flankenerkennung = entprellen = taster;
> Unter C ist die Bedeutung eindeutig, alle Variablen werden auf den
> gleichen Wert gesetzt.

Nein, dass ist nicht der fall.
flankenerkennung = entprellen = taster;
entspricht:
entprellen = taster;
flankenerkennung = entprellen;

Insbesondere wenn entprellen volatile ist kann sich das zwischendurch 
durchaus ändern.

Autor: Georg B. (diereinegier)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das wird von rechts nach links ausgeführt und wenn die beteiligten Typen 
Klassen sind, dann kann man das in der Dokumentation oder im Quelltext 
der Klasse nachlesen, die den Zuweisungsoperator und evtl. noch 
Type-Cast-Operatoren implementiert.

Autor: Oliver S. (oliverso)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Und all das bräuchte nicht weiter diskutiert werden, wenn man solche 
Konstrukte einfach nicht nutzt.

Oliver
P.S:
Häufig sieht man das auch in C++ eigentlich überhaupt nicht. Da gibt es 
eigentlich hier nur den einen, der das Beispiel von oben auch verbrochen 
hat.

Das Beispiel zeigt genau den Grund, warum man das nicht machen soll. Das 
sieht der Verursacher zwar anders (der findet seine Idee toll), aber 
egal. Murks bleibt Murks.

: Bearbeitet durch User
Autor: Oliver S. (oliverso)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Olaf B. (Firma: OBUP) (obrecht)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> sieht man ... in C++ eigentlich überhaupt nicht
wird bei Ruby öfters verwandt. In C++ nicht.

Autor: Oliver S. (oliverso)
Datum:

Bewertung
2 lesenswert
nicht lesenswert
Das o.a. Beispiel stammt von hier:

Beitrag "Re: C/C++ Objektmethoden"

und basiert auf unerwartetem Operator-Overloading. Die Grundregel des 
"principle of least surprise", die das verletzt, gilt genauso für Rust 
und andere Programmiersprachen.

Oliver

Autor: Olaf B. (Firma: OBUP) (obrecht)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bei C++ FACK

bei Ruby meckert nicht mal der Linter, der dort den Code checkt. :-)

Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> Das o.a. Beispiel stammt von hier:
>
> Beitrag "Re: C/C++ Objektmethoden"
>
> und basiert auf unerwartetem Operator-Overloading. Die Grundregel des
> "principle of least surprise", die das verletzt, gilt genauso für Rust
> und andere Programmiersprachen.

Danke für den Link, das erklärt vieles.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> In C++ sieht man ja oft solche Mehrfachzuweisungen:
>
> counter = flankenerkennung = entprellen = taster;
> 
> Unter C ist die Bedeutung eindeutig, alle Variablen werden auf den
> gleichen Wert gesetzt.
> Unter C++ ist die Bedeutung aber eine völlig andere. Wo kann man
> nachlesen, was das bedeutet?

Der Kopierzuweisungsoperator ist ein C++ ein Operator, den man selbst 
definieren und überladen kann. Was der Operator dann tut, ist der 
Sprache egal. Allerdings (wie oben schon geschrieben), sollte man dabei 
die übliche Erwartungshaltung erfüllen, und zwar der Operator (etwa bei: 
lhs = rhs) hat als Resultat das lhs-Objekt und übt einen bestimmten 
Seiteneffekt auf lhs aus, nämlich kopiert die non-const Attribute.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
DPA schrieb:
> Peter D. schrieb:
>> In C++ sieht man ja oft solche Mehrfachzuweisungen:counter =
>> flankenerkennung = entprellen = taster;
>> Unter C ist die Bedeutung eindeutig, alle Variablen werden auf den
>> gleichen Wert gesetzt.
>
> Nein, dass ist nicht der fall.
>
>  flankenerkennung = entprellen = taster;
>
> entspricht:
>
>  entprellen = taster;
>  flankenerkennung = entprellen;
>
> Insbesondere wenn entprellen volatile ist kann sich das zwischendurch
> durchaus ändern.

Auch implizite Typkonvertierungen können zu Unterschieden führen:

#include <stdio.h>
#include <stdint.h>

int main(void) {
  double d;
  int16_t i16;
  uint8_t ui8;

  ui8 = i16 = d = -1234.5;

  printf("d=%f, i16=%d, u8=%u\n", d, i16, ui8);
}

ergibt

d=-1234.500000, i16=-1234, u8=46


Olaf B. schrieb:
> wird bei Ruby öfters verwandt. In C++ nicht.

In Ruby und Python ist die Zuweisung an gewöhnliche Variablen (also
keine Membervariablen) nicht überladbar, und es gibt keine impliziten
Typkonvertierungen, weswegen es dort diesbezüglich keine Überraschungen
gibt.

Ich verwende die Mehrfachzuweisung auch in C und C++, aber nur für
primitive Datentypen (int, double usw.) und nur für Variablen gleichen
Typs. Damit sind Überraschungen ebenfalls ausgeschlossen.


Oliver S. schrieb:
> Das o.a. Beispiel stammt von hier:
>
> Beitrag "Re: C/C++ Objektmethoden"

Das ist wirklich gruselig, noch gruseliger als die Vergewaltigung der
Bitshift- als I/O-Operatoren in iostream. Hätte der Fanboy statt des =
wenigstens das ohnehin schon versaute << genommen, wäre die Überraschung
nicht ganz so heftig.

: Bearbeitet durch Moderator
Autor: Heiko L. (zer0)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:
> Das ist wirklich gruselig, noch gruseliger als die Vergewaltigung der
> Bitshift- als I/O-Operatoren in iostream. Hätte der Fanboy statt des =
> wenigstens das ohnehin schon versaute << genommen, wäre die Überraschung
> nicht ganz so heftig.

Nur, dass << von links nach rechts ausgewertet wird.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heiko L. schrieb:
> Nur, dass << von links nach rechts ausgewertet wird.

Stimmt. Dann also andersherum:

  taster >> entprellen >> flankenerkennung >> counter;

Das passt ohnehin besser zu der hierzulande üblichen Leserichtung.

Oder auch

  taster | entprellen | flankenerkennung | counter;

Das erinnert an eine Shell-Pipline, die eine ähnliche Funktion hat.

Ein Rest des bösen Überraschungseffekts bleibt aber dennoch.

Warum müssen dafür unbedingt die Operatoren missbraucht werden, wenn es
auch mit benamsten Memberfunktionen geht?

Also so:

taster.pipe(entprellen).pipe(flankenerkennung).pipe(counter);

Oder, wenn die Memberfunktionsnamen eher wie Infixoperatoren aussehen
sollen, so:

taster .pipe (entprellen) .pipe (flankenerkennung) .pipe (counter);

Autor: Heiko L. (zer0)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, richtig. Bei dem Beispiel mit den Zuweisungen würde ich davon 
ausgehen, dass das Objekt ganz Rechts, also "taster", const sein könnte. 
Beim >> würde ich darauf nicht wetten.
Insgesamt wäre ich bei Operatoren vorsichtig, ihnen eine Bedeutung zu 
geben, die nicht "vom Standard diktiert" wurde. Wenn die Bedeutung kein 
common-sense ist, führt der Verzicht auf die Benamung schlicht dazu, 
dass man nur noch mit irgendeinem wildcard-symbol konfrontiert ist. 
Schlimmer noch, als das bei benannten Funktionen z.T. schon der Fall 
ist.
Die >>-Kette gibt z.B. klassischer Weise das Objekt links zurück, nicht 
das rechte.

: Bearbeitet durch User
Autor: Oliver S. (oliverso)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heiko L. schrieb:
> Insgesamt wäre ich bei Operatoren vorsichtig, ihnen eine Bedeutung zu
> geben, die nicht "vom Standard diktiert" wurde.

Die C++ Core Guidelines haben wohl nicht ohne Grund eine eigene Regel 
dafür kreiert, und bringen das auf den Punkt:

C.61: A copy operation should copy

Oliver

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heiko L. schrieb:
> Insgesamt wäre ich bei Operatoren vorsichtig, ihnen eine Bedeutung zu
> geben, die nicht "vom Standard diktiert" wurde. Wenn die Bedeutung kein
> common-sense ist, führt der Verzicht auf die Benamung schlicht dazu,
> dass man nur noch mit irgendeinem wildcard-symbol konfrontiert ist.

Dann schau dir mal boost.spirit an. Da treiben sie die Operator Abuse 
auf die Spitze. Siehe https://de.wikipedia.org/wiki/Spirit_(Parser)

Autor: Heiko L. (zer0)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Heiko L. schrieb:
>> Insgesamt wäre ich bei Operatoren vorsichtig, ihnen eine Bedeutung zu
>> geben, die nicht "vom Standard diktiert" wurde. Wenn die Bedeutung kein
>> common-sense ist, führt der Verzicht auf die Benamung schlicht dazu,
>> dass man nur noch mit irgendeinem wildcard-symbol konfrontiert ist.
>
> Dann schau dir mal boost.spirit an. Da treiben sie die Operator Abuse
> auf die Spitze. Siehe https://de.wikipedia.org/wiki/Spirit_(Parser)

Wobei das ein in sich abgeschlossenes Modul ist und die Operatoren 
keinerlei Verwendung außerhalb der Definition der Grammatik anstreben.

Autor: Wilhelm M. (wimalopaan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heiko L. schrieb:
> Rolf M. schrieb:
>> Heiko L. schrieb:
>>> Insgesamt wäre ich bei Operatoren vorsichtig, ihnen eine Bedeutung zu
>>> geben, die nicht "vom Standard diktiert" wurde. Wenn die Bedeutung kein
>>> common-sense ist, führt der Verzicht auf die Benamung schlicht dazu,
>>> dass man nur noch mit irgendeinem wildcard-symbol konfrontiert ist.
>>
>> Dann schau dir mal boost.spirit an. Da treiben sie die Operator Abuse
>> auf die Spitze. Siehe https://de.wikipedia.org/wiki/Spirit_(Parser)
>
> Wobei das ein in sich abgeschlossenes Modul ist und die Operatoren
> keinerlei Verwendung außerhalb der Definition der Grammatik anstreben.

Die Grammatik hat aber nichts mit der Semantik zu tun!
Da verwechselt Du was. Es gibt nichts außerhalb der Grammatik bei einer 
formalen Sprache.

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]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [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.