Forum: Mikrocontroller und Digitale Elektronik Zwei defines verbinden


von Großes F. (112)


Lesenswert?

Hallo,

ich möchte einen Portpin mittels Defines zwischen den Zuständen 
Input/Tristate und Output/High umschalten, d.h. ich Muss sowohl DDxn und 
PortXn jeweils von 11 auf 00 umschalten.

Bisher habe ich für jede einzelne Operation ein "Reinschrift-Define".

#define I0 (PORTD |= (1<<PD4) )
#define I0_out (DDRD |= ( 1 << DDD4))

Kann ich diese beiden Operationen in ein einziges Define reinquetschen, 
so dass ich im Code dann nurnoch z.B. "StromausgangIO;" schreibe und 
dann automatisch die beiden CodeOperationen von oben ausgeführt werden?`

mfg

von Luddi (Gast)


Lesenswert?

über ein define wird das schwierig
könntest dir dafür aber einfach eine Funktion schreiben, mit dieser 
könntest du auch ein togglen einfach umsetzen

von Volkmar D. (volkmar)


Lesenswert?

Großes Fragezeichen schrieb:
> Kann ich diese beiden Operationen in ein einziges Define reinquetschen,

Ja:
1
#define tu_was {(PORTD |= (1<<PD4);DDRD |= ( 1 << DDD4)}

Wie üblich mit Semikolon die Anweisungen trennen und mit geschweiften 
Klammern umfassen.

von JOY (Gast)


Lesenswert?

Hallo, geht so etwas nicht:

wenn:
#define StromausgangIO

dann:
#ifdef StromausgangIO

#define I0 (PORTD |= (1<<PD4) )
#define I0_out (DDRD |= ( 1 << DDD4))

#endif

Gruß Johannes

von Großes F. (112)


Lesenswert?

danke, die geschweifte Klammer funktioniert!

von Björn C. (bjoernc) Benutzerseite


Lesenswert?

Ich muss Volkmar Dierkes auch zustimmen zwei Befehle in ein define ist 
nun nicht der akt aber ich würde statt:
1
#define tu_was {PORTD |= (1<<PD4);DDRD |= ( 1 << DDD4)}
dann doch lieber zu sowas tendieren:
1
#define do_someting {\
2
do{\
3
PORTD |= (1<<PD4);\
4
DDRD |= ( 1 << DDD4);\
5
}while(0)
Das do{}while(0) mag jetzt im ersten Moment komisch aussehen hat aber 
folgenden Vorteil man schreibt folgendes:
1
if(Condition)
2
tu_was;
führt zu:
1
if(Condition)
2
PORTD |= (1<<PD4);
3
DDRD |= ( 1 << DDD4);
Hier bei wird NUR PORTD |= (1<<PD4); je nach condition ausgeführt das 
DDRD aber unabhängig von der if-Abfrage. Anders sieht es bei der do 
while() schleife aus. Dort sind die Befehle in einem Befehlsblock 
untergebracht und man umgeht diese kleine Falle (mit zT. sehr 
frickeligen Fehlern). Ich hoffe ich habe den unterschied bzw. die 
Begründung einigermaßen verständlich beschrieben.

von Chris H. (hergi)


Lesenswert?

Solange die geschweiften Klammern außenrum stehen sollte es doch dabei 
kein Problem geben, oder?

von Thomas E. (thomase)


Lesenswert?

Björn Cassens schrieb:
> if(Condition)
> tu_was;
> führt zu:if(Condition)
> PORTD |= (1<<PD4);
> DDRD |= ( 1 << DDD4);
Nein.

Das
> #define tu_was {PORTD |= (1<<PD4);DDRD |= ( 1 << DDD4)}
                 ^                                      ^
ergibt

{
 PORTD |= (1<<PD4);
 DDRD |= ( 1 << DDD4);
}

mfg.

von Stefan E. (sternst)


Lesenswert?

Thomas Eckmann schrieb:
> ergibt
>
> {
>  PORTD |= (1<<PD4);
>  DDRD |= ( 1 << DDD4);
> }

Nicht ganz, aus "tu_was;" wird dann
1
{
2
  PORTD |= (1<<PD4);
3
  DDRD |= ( 1 << DDD4);
4
};
Und das Semikolon kann zum Problem werden.
1
if (...)
2
    tu_was;
3
else
funktioniert z.B. damit nicht.
Die do/while Variante hat diesen Nachteil nicht.

von Thomas E. (thomase)


Lesenswert?

Stefan Ernst schrieb:
> Nicht ganz, aus "tu_was;" wird dann
Ja und? Da gehört kein Semikolon hin.

mfg.

von Stefan E. (sternst)


Lesenswert?

Thomas Eckmann schrieb:
>> Nicht ganz, aus "tu_was;" wird dann
> Ja und? Da gehört kein Semikolon hin.

Genau, man wird gezwungen
1
if (...)
2
    tu_was
3
else
zu schreiben, und das ist doch "unnatürlich".

von Oliver (Gast)


Lesenswert?

Diese define-Funktions-Abkürzungs-Unsitte ist einfach Murks.

Ganz generell sind defines defines, und Funktionen Funktionen. Und dabei 
sollte man möglichst auch bleiben. Und nur in ganz wenigen, speziellen 
Ausnahmefällen ist es sinnvoll, das zu mischen. In diesem Fall nicht.

Da gehört das hier hin:
1
  static inline void StromausgangIO(void)
2
  {
3
    PORTD |= 1<<PD4;
4
    DDRD |=  1 << DDD4;
5
  }

In diesem Sinne...

Oliver

von (prx) A. K. (prx)


Lesenswert?

Stefan Ernst schrieb:

> else[/c]zu schreiben, und das ist doch "unnatürlich".

Es sei denn man hat mit Pascal angefangen.

von Thomas E. (thomase)


Lesenswert?

Stefan Ernst schrieb:
> zu schreiben, und das ist doch "unnatürlich".
Dann schreibst du da ein Semikolon hin und gut ist.
Der do-while-Kram ist Schwachsinn.

mfg.

von (prx) A. K. (prx)


Lesenswert?

Thomas Eckmann schrieb:

> Dann schreibst du da ein Semikolon hin und gut ist.

Der Ästhetik ist damit gedient, aber der Compiler mosert.
Weil der "if (cond) { stmts; }; else ..." nicht mag,
jedoch "if (cond) do{ stmts; }while(0); else ..." schon.

von Thomas E. (thomase)


Lesenswert?

A. K. schrieb:
> Der Ästhetik ist damit gedient, aber der Compiler mosert.
> Weil der "if (cond) { stmts; }; else ..." nicht mag,
> jedoch "if (cond) do{ stmts; }while(0); else ..." schon.
Und deswegen schreib' ich da auch kein Semikolon nicht hin.

mfg.

von Karl H. (kbuchegg)


Lesenswert?

Thomas Eckmann schrieb:
> Stefan Ernst schrieb:
>> zu schreiben, und das ist doch "unnatürlich".
> Dann schreibst du da ein Semikolon hin und gut ist.

Nicht ganz. Es ist eben nicht gut

> Der do-while-Kram ist Schwachsinn.

Leider ist er es nicht.

Aber ich muss Oliver recht geben.
Man sollte nicht versuchen Dinge in Makros zu quetschen, die in 
Funktionen viel besser aufgehoben sind.

von Volkmar D. (volkmar)


Lesenswert?

Die Variante mit dem do{}while(0) hat tatsächlich den Vorteil, daß sie 
auch für den if-else-Fall funktioniert wenn man dort keine geschweiften 
Klammern verwendet. Sollte man also eher als meinen Vorschlag verwenden, 
wenn es denn mit den defines sein soll.

Die Variante als Funktion mit inline ist sicherlich nicht zu verachten.

von Thomas E. (thomase)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Nicht ganz. Es ist eben nicht gut
Natürlich nicht.
>> Der do-while-Kram ist Schwachsinn.
> Leider ist er es nicht.
Also bevor ich sowas da hinschreibe, lass' ich doch lieber das Semikolon 
weg, was ich bei "defines" sowieso mache. Aber das muß ja jeder selber 
wissen.

Karl Heinz Buchegger schrieb:
> Aber ich muss Oliver recht geben.
Ich auch. Aber die Frage war ja nunmal anders gestellt. Und es geht ja 
auch.

mfg.

von (prx) A. K. (prx)


Lesenswert?

Thomas Eckmann schrieb:

> Also bevor sowas da hinschreibe, lass' ich doch lieber das Semikolon
> weg, was ich bei "defines" sowieso mache.

Dann muss man aber wissen, dass es sich um ein Makro und keinen 
Funktionsaufruf handelt. Deshalb ziehe ich es vor, Makros so zu 
formulieren, dass sie Funktionen möglichst ähnlich sind.

von Thomas E. (thomase)


Lesenswert?

A. K. schrieb:
> Dann muss man aber wissen, dass es sich um ein Makro und keinen
> Funktionsaufruf handelt.
Das erkenne ich bei mir an der Schreibweise. Hat den Vorteil, daß man 
jedesmal auch wirklch genau weiss, dass es sich um ein Makro handelt. 
Denn Makros können den Code auch mächtig aufblähen, was bei Funktionen 
nicht der Fall ist.

mfg.

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

Stefan Ernst schrieb:
> Genau, man wird gezwungenif (...)
>     tu_was
> elsezu schreiben, und das ist doch "unnatürlich".

Nein, man kann zig ; irgendwo in Leere Zeilen im Code und ans Ende von 
Zeilen schreiben - macht gar nichts aus.

a = a+1;;; funktioniert tadellos.

von Thomas E. (thomase)


Lesenswert?

Nils S. schrieb:
> a = a+1;;; funktioniert tadellos.
Aber bei "if{};;;;; else{}" gibt das Mecker.

mfg.

von (prx) A. K. (prx)


Lesenswert?

Nils S. schrieb:

> Nein, man kann zig ; irgendwo in Leere Zeilen im Code und ans Ende von
> Zeilen schreiben - macht gar nichts aus.

Aber nicht hinter eine geschlossene geschweifte Klammer, wenn's danach 
aus einem umgreifenden Statement mit "else" oder "while" weiter geht.

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

Thomas Eckmann schrieb:
> Aber bei "if{};;;;; else{}" gibt das Mecker

Aber so wird das nicht dastehen:
1
#define BLA { PORTA = 0xff; PORTB = 0x00; }
2
#define BLUBB PORTC = 0xaa;
3
4
if(x) BLA
5
wird zu:
6
if(x) {
7
     PORTA = 0xff; PORTB = 0x00;
8
}
9
10
if(y) BLUBB
11
wird zu:
12
if(y) PORTC = 0xaa;
Es gibt keinen Grund ein "{ .... };" irgendwo hinzusetzen, ausser bei 
typedefs, Array-Auffüllern usw, aber nicht bei Anweisungen.

von Oliver (Gast)


Lesenswert?

Nils S. schrieb:
> if(x) BLA
> wird zu:

Es geht aber darum, daß hinter jede Anweisung in C ein Semikolon gehört. 
Und
1
    
2
if(x) 
3
   BLA;
4
else
5
   BLUBB;

geht eben in die Hose.

Oliver

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

Oliver schrieb:
> Es geht aber darum, daß hinter jede Anweisung in C ein Semikolon gehört.
> Und
>
> if(x)
>    BLA;
> else
>    BLUBB;
>
> geht eben in die Hose.

Ja natürlich, if.... *;* ... else geht nunmal nicht, aber wieso sollte 
man das machen? Man macht ja auch nicht if(x) { ... }; else { ... }

von asd (Gast)


Lesenswert?

Ich denke ich stimme hier mit den meisten anderen überein, dass es eine 
schlechte Idee ist für diesen Anwendungszweck überhaupt #defines zu 
nehmen.

Ganz normale Funktion und fertig, meinetwegen noch "inline" davor 
schreiben, obwohl der Compiler schon schlau genug sein sollte sowas 
selbst zu entscheiden.

von Karl H. (kbuchegg)


Lesenswert?

Nils S. schrieb:
> Oliver schrieb:
>> Es geht aber darum, daß hinter jede Anweisung in C ein Semikolon gehört.
>> Und
>>
>> if(x)
>>    BLA;
>> else
>>    BLUBB;
>>
>> geht eben in die Hose.
>
> Ja natürlich, if.... *;* ... else geht nunmal nicht, aber wieso sollte
> man das machen?

Genau darum geht es doch

  if(x)
    BLA;
  else
    BLUBB;

ist
* für jemanden, der nicht weiß was sich hinter BLA bzw BLUBB versteckt
  völlig natürlich. Und das kann auch ein und derselbe Programmierer
  sein, wenn nur genug Zeit ziwschen der Makroerstellung und einer
  notwendigen Programmänderung steckt.

* im Falle, dass ein Makro tatsächlich nur 1 Statement substitiert

#define BLA   PORTC &= (1<<PC0)
#define BLUBB PORTC |= (1<<PC0)

  muss es nämlich

  if(x)
    BLA;
  else
    BLUBB;

  heissen! D.h. die Syntax in der Verwendung richtet sich plötzlich
  danach, was konkret im Makrotext steckt!

> Man macht ja auch nicht if(x) { ... }; else { ... }
Natürlich nicht. Der Unterschied ist nur: Da sehe ich das Problem direkt 
an der Stelle, die mir der Compiler anmeckert. Bei der Makrolösung sehe 
ich das nicht unbedingt sofort. Geh in diverse Newsgroups. Ich wette 
innerhalb von 2 Wochen tritt genau dieses Problem mindestens 4 mal auf, 
dass der Frager mit einerm "else without matching if" dasteht und nicht 
weiter weiß.

Es gibt nur 2 Lösungen
* entweder das ganze in eine Funktion verschieben
* oder das Makro so verpacken, dass es in der Substitution auf jeden
  Fall als ein einziges Statement substituiert. Und genau deswegen
  verpackt man alles in ein do - while Statement, das vom Optimizer
  wieder rausgeschmissen wird.

von Thomas E. (thomase)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Der Unterschied ist nur: Da sehe ich das Problem direkt
> an der Stelle, die mir der Compiler anmeckert. Bei der Makrolösung sehe
> ich das nicht unbedingt sofort
Aber immerhin meckert er das an. Schlimm wäre, wenn er es, wie diese 
Fehlkonstrution "if(a=b)" durchwinken würde.

Trotzdem finde ich diese do-while-Konstruktion grausig, auch wenn sie 
ihren Zweck hundertprozentig erfüllt.

mfg.

von Karl H. (kbuchegg)


Lesenswert?

Thomas Eckmann schrieb:

> Trotzdem finde ich diese do-while-Konstruktion grausig,

Oh. Da bin ich voll auf deiner Seite!
Ich finde überhaupt, dass man sich in C von solchen Makro-Hacks 
distanzieren sollte. Im Endeffekt bringt es meistens nichts, wenn man 
Makros zu extensiv für Dinge nutzt, für die sie nicht gedacht waren.

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

Thomas Eckmann schrieb:
> wie diese
> Fehlkonstrution "if(a=b)" durchwinken würde.

Das ist keine Fehlkonstruktion. Er weisst a den Inhalt von b zu. Nur was 
genau er fürs if nimmt weiss ich nicht - 1/0 für "Erfolgreich 
zugewiesen"/"habe nichts zurückzugeben" oder den Inhalt der Variable - 
steht sicher irgendwo.

Tunlichst vermeiden und durchwinken tut der Compiler das aber trotzdem 
nicht:
1
ktee@DrHomo ~ $ cat test.c 
2
#include <stdio.h>
3
4
int main() {
5
        int a=0, b=2;
6
        if(a=b) { printf("aha\n"); }
7
8
        return 0;
9
}
10
ktee@DrHomo ~ $ gcc -Wall test.c            
11
test.c: In function 'main':
12
test.c:5: warning: suggest parentheses around assignment used as truth value
13
ktee@DrHomo ~ $ ./a.out 
14
aha

von (prx) A. K. (prx)


Lesenswert?

Nils S. schrieb:

> Das ist keine Fehlkonstruktion. Er weisst a den Inhalt von b zu. Nur was
> genau er fürs if nimmt weiss ich nicht

Den Inhalt von a nach der Zuweisung, mit != 0.

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

A. K. schrieb:
> Den Inhalt von a nach der Zuweisung, mit != 0.

Okay, nun bin ich auch gleich etwas schlauer ;)

Ich hab vor kurzem erst sowas haufenweise gesehen. Ich glaube das war in 
irgendeinem 6502/SID/C64/...-Emu-Code, den ich durchgesehen hab. Wenn 
ich wieder sehe, zeig ichs mal, sieht ganz ganz böse aus beim 
Compilieren.


Achja, ich vergaß:

-Wall immer einschalten, wer ohne compiliert ist faul. Wer sich nicht 
durchringen kann, die warnungen gleich zu beheben, nimmt noch -Werror. 
-Wextra hab ich auch meistens mit drin.

Da kommen dann solche "Konstrukte" gar nicht erst zustande.

von Thomas E. (thomase)


Lesenswert?

Nils S. schrieb:
> Er weisst a den Inhalt von b zu.
wow!
Aber nur, wenn a vorher grün war.
Nur beabsichtigt ist das meistens nicht.

mfg.

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

Thomas Eckmann schrieb:
> wow!

wow! Diskussionsresistente Leute, selten gesehen hier...

von Thomas E. (thomase)


Lesenswert?

Nils S. schrieb:
> Nur was genau er fürs if nimmt weiss ich nicht
Gegen die Qualität deiner Beiträge kommt man natürlich schwer an.

mfg.

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

Thomas Eckmann schrieb:
> Gegen die Qualität deiner Beiträge kommt man natürlich schwer an.

Bisher haben sich noch nicht viele beschwert und weil Hansel X das 
meint, juckt mich das nicht.
Wenn ichs nicht besser weiss, schreib ich das eben auch.

von Thomas E. (thomase)


Lesenswert?

Nils S. schrieb:
> Wenn ichs nicht besser weiss, schreib ich das eben auch.
Und wen interessiert das?
Und wer ist Hansel X?

Wollen wir jetzt beleidigen.

mfg.

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

>Schlimm wäre, wenn er es, wie diese
>Fehlkonstrution "if(a=b)" durchwinken würde.
Es ist keine Fehlkonstruktion, aber hässlich und er winkt es nicht 
einfach durch.
Nur was er genau damit macht, weiss/wusste ich nicht, da man sowas nicht 
macht, siehe Satz weiter oben, Herr Oberlehrer.

Wollen tu ich gar nix.

von Markus (Gast)


Lesenswert?

Bei dem Rumgezicke könnte man meinen ihr beide seid Mädchen und keine 
Nerds

von Karl H. (kbuchegg)


Lesenswert?

In C ist dieses
   a = b = c;

ausdrücklich erlaubt und wird als
   a = ( b = c );

angesehen. a bekommt dabei den Wert den b durch die Zuweisung erhalten 
hat. Achtung: Das ist nicht notwendigerweise identisch zu: a und b haben 
den Wert von c!

"Sinnvoll" ist das zb

  double x, y;

  x = y = 0.0;

Um zu verstehen, warum man diese Operation überhaupt erlaubt hat, muss 
man berücksichtigen, dass Optimizer zur Zeit als C entstand noch 
weitgehend in den Kinderschuhen steckten. D.h. hier half man ganz 
einfach dem Compiler besseren Code zu produzieren.

von Klaus W. (mfgkw)


Lesenswert?

Abgesehen davon kann man zwei Operationen auch mit dem Kommaperator zu 
einer verbinden, ohne ein Semikolon dazwischen zu setzen.

von Björn C. (bjoernc) Benutzerseite


Lesenswert?

bei if(a=b)kann man genausogut schreiben if(b), der Wert der Operation 
also a=b liefert den zu schreibenden Wert (in diesem Falle b), das ist 
übrigens auch der Grund warum man folgendes machen kann:
1
int i,j,k,l;
2
i=j=k=l=0;

das die Makrogeschichte mit dem do{}while() nicht schön ist, ist klar, 
dafür gibts inline. Ab und zu kann aber ein solches Makro schon sinnvoll 
sein - aber ich habe dies bisher nur einmal gehabt, wo dies sinnvoll war 
(dort durften die Register vom Compiler nicht angefasst werden und das 
Makro enthielt dann entsprechende Anweisungen die Register auf einen 
anderen Stack zu legen).

von Karl H. (kbuchegg)


Lesenswert?

> da man sowas nicht macht, siehe Satz weiter oben

wenn man weiß, was man tut, kann man dieses Feature durchaus sinnvoll 
einsetzen
1
   while( ( c = getc() ) != '\n' )
2
     putc( c );
ist ein sinnvolles Konstrukt.

Die Alternative, ohne dieses 'Feature', lautet
1
   c = getc();
2
   while( c != '\n' ) {
3
     putc( c );
4
     c = getc();
5
   }
und ist deutlich umständlicher zu schreiben. Man beachte, dass im ersten 
der Aufruf für die Eingabefunktion nur einmal im Code vorkommt, im 
zweiten Fall aber zweimal. D.h. auch wartungstechnisch ist die erste 
Variante besser, weil es dort gar nicht möglich ist, unterschiedliche 
Einlesefunktionen aus Versehen zu benutzen.


C ist eben eine Sprache, die man von der Pieke auf mit all ihren 
Möglichkeiten lernen muss. Wer eine Lulutante braucht, ist bei C an der 
falschen Adresse.

von Oliver (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> Abgesehen davon kann man zwei Operationen auch mit dem Kommaperator zu
> einer verbinden, ohne ein Semikolon dazwischen zu setzen.

Genau. Das, verbunden mit den hier diskutierten define-Funktions-Makros, 
gewürzt mit ein paar Fragezeichenoperatoren und anderen grusligen 
Überbleibseln  aus der C-Lochkarten-Steinzeit bringt einen dann im 
obfuscated c contest ganz weit nach vorne ;)

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Oliver schrieb:

> Überbleibseln  aus der C-Lochkarten-Steinzeit bringt einen dann im
> obfuscated c contest ganz weit nach vorne ;)

:-)

Nicht .... wirklich.

Im OCCC muss man schon ein wenig mehr drauf haben.

Aber den Kommaoperator hätte man sich wirklich sparen sollen. Für den 
kenn ich auch keine sinnvolle Anwendung. Der ist einfach nur ekelig.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> wenn man weiß, was man tut, kann man dieses Feature
> durchaus sinnvoll einsetzen
Das geht in Java auch, und kann wie du schriebst auch durchaus sinnvoll 
eingesetzt werden.

Das eigentliche Problem ist, das der Compiler integer an der Stelle  wo 
ein boolean (den es ja so in C nicht gibt) benötigt wird akzeptiert.

Karl Heinz Buchegger schrieb:
> Aber den Kommaoperator hätte man sich wirklich sparen sollen. Für den
> kenn ich auch keine sinnvolle Anwendung. Der ist einfach nur ekelig.
Initialisierungen und inkrementieren in FOR Schleifen? ;)

von Karl H. (kbuchegg)


Lesenswert?

Läubi .. schrieb:
> Karl Heinz Buchegger schrieb:
>> wenn man weiß, was man tut, kann man dieses Feature
>> durchaus sinnvoll einsetzen
> Das geht in Java auch, und kann wie du schriebst auch durchaus sinnvoll
> eingesetzt werden.
>
> Das eigentliche Problem ist, das der Compiler integer an der Stelle  wo
> ein boolean (den es ja so in C nicht gibt) benötigt wird akzeptiert.

Die genau Syntax lautet

   if( expression )

d.h. alles was in C eine expression (also ein Ausdruck der zu einem Wert 
ausgewertet werden kann) ist, kann dort benutzt werden. Wobei natürlich 
die von dir angesprochene Konvention gilt, dass alles was 0 ist, als 
logisch FALSE gewertet wird.
Und auch eine Zuweisung ist in C eine expression die einen Wert liefert, 
eben den Wert nach der Zuweisung.

In diesem Sinne sind auch Vergleiche in C ganz einfach nur Operatoren 
wie es auch + und - sind, die einen Wert liefern.
   i = 2*(a > b);
ist völlig legales C und eine direkte Konsequenz daraus.

Das hat Vorteile, hat aber auch Nachteile.

Klar hätte man auch eine boolean Expression fordern können
  if( bool_expression )
hätte dann aber einen neuen Datentyp benötigt und für Pointer wieder 
eine Sonderregel einführen müssen, wie ein Pointer auf einen bool 
abgebildet wird, was an und für sich kein Beinbruch gewesen wäre.

Aber wie es eben so ist: Wenn man erst mal eine Sprachdefinition 
draussen hat und die ersten Programme geschrieben hat, dann ändert man 
die Syntax nicht mehr so gerne, wenn es nicht unbedingt sein muss bzw. 
die Auswirkungen überschaubar sind. K&R konnten damals nicht wissen, 
welchen Siegeszug C 20 Jahre später antreten wird. Sie brauchten einen 
Nachfolger für B um ihr Unix neu zu implementieren.

von (prx) A. K. (prx)


Lesenswert?

Björn Cassens schrieb:

> bei if(a=b)kann man genausogut schreiben if(b), der Wert der Operation
> also a=b liefert den zu schreibenden Wert (in diesem Falle b)

Meinst du? Dann probier mal:
1
char a;
2
int b = 256;
3
if (a=b)

von Karl H. (kbuchegg)


Lesenswert?

Läubi .. schrieb:

> Karl Heinz Buchegger schrieb:
>> Aber den Kommaoperator hätte man sich wirklich sparen sollen. Für den
>> kenn ich auch keine sinnvolle Anwendung. Der ist einfach nur ekelig.
> Initialisierungen und inkrementieren in FOR Schleifen? ;)

Oops. Genau!

von Karl H. (kbuchegg)


Lesenswert?

Björn Cassens schrieb:

> also a=b liefert den zu schreibenden Wert

den tatsächlich geschriebenen Wert.
Das ist ein Unterschied!


  double a, b;
  int    c;

  a = c = b = 3.5;

b hat den Wert 3.5
c hat den Wert 3
a hat den Wert 3.0  (!)

von (prx) A. K. (prx)


Lesenswert?

Karl Heinz Buchegger schrieb:

> den tatsächlich geschriebenen Wert.

Manchmal nicht einmal den:
   if (UART_DATA_REGISTER = 'x') ...
Hier hat der für die Bedingung verwendete Wert keinerlei Zusammenhang 
mit dem geschriebenen Wert 'x', die übliche Funktion solcher Register 
vorausgesetzt.

Zugegeben, dieses Beispiel ist etwas bös. ;-)

von Klaus W. (mfgkw)


Lesenswert?

?

Ich würde mich schwer wundern, wenn hier nicht der zugewiesene Wert 
geliefert würde.

von Klaus W. (mfgkw)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Oliver schrieb:
>
>> Überbleibseln  aus der C-Lochkarten-Steinzeit bringt einen dann im
>> obfuscated c contest ganz weit nach vorne ;)
>
> :-)
>
> Nicht .... wirklich.
>
> Im OCCC muss man schon ein wenig mehr drauf haben.
>
> Aber den Kommaoperator hätte man sich wirklich sparen sollen. Für den
> kenn ich auch keine sinnvolle Anwendung. Der ist einfach nur ekelig.

Der ist genau für solche Fälle gedacht.
Wenn man ihn nun just da, wo man ihn sinnvoll nutzen könnte, ignoriert, 
kann man sich natürlich schwerlich eine sinnvolle Anwendung denken :-)

Ich sehe nichts, was dagegen spricht, außer daß viele Leute ihn nicht 
nehmen, warum auch immer.

Karl Heinz Buchegger schrieb:
> C ist eben eine Sprache, die man von der Pieke auf mit all ihren
> Möglichkeiten lernen muss. Wer eine Lulutante braucht, ist bei C an der
> falschen Adresse.

... und dann die Möglichkeiten wieder ignorieren :-))

von Klaus W. (mfgkw)


Lesenswert?

Zugegebenermaßen ist nicht alles schön, was man mit C treiben kann:
http://en.wikipedia.org/wiki/Duff's_device

von Stefan E. (sternst)


Lesenswert?

Klaus Wachtler schrieb:
> Ich würde mich schwer wundern, wenn hier nicht der zugewiesene Wert
> geliefert würde.

Das Ergebnis einer Zuweisung ist nicht der ursprünglich zugewiesene 
Wert, sondern der Inhalt der linken Seite nach der Zuweisung. Und da die 
linke Seite hier volatile sein dürfte, wird zur "Ergebnisermittlung" die 
linke Seite tatsächlich gelesen ...
na, ich denke du weißt schon, worauf das jetzt hinausläuft. ;-)

von Stefan E. (sternst)


Lesenswert?

Nachtrag:
Im Code generiert durch avr-gcc findet sich dieses Verhalten allerdings 
nicht. Da wird eine solche Bedingung zu always-true optimiert. 
Volatile-Bug vom GCC?

von Klaus W. (mfgkw)


Lesenswert?

So ganz überzeugt bin ich noch nicht.
Im K&R lese ich: "... daß ein Zuweisungsoperator den zugewiesenen Wert 
als Resultat liefert und in Ausdrücken verwendet werden kann..."

von Stefan E. (sternst)


Lesenswert?

Der Standard sagt:
1
An assignment expression has the value of the left operand after
2
the assignment

von Klaus W. (mfgkw)


Lesenswert?

Das ist das Schöne an Standards....

Also der gcc schert sich nicht drum, sagst du (welchen Standard auch 
immer du meinst).
Daraufhin habe ich mal mit dem Visual C/C++ (14.00.50727.762 for 80x86) 
ein Stück übersetzt aus Neugier:
1
  int             a = 0;
2
  volatile int    b = 0;
3
  volatile int   *pb = &b;
4
5
  a = b = 32;
6
  // wird zu:
7
  //    mov     DWORD PTR _b$[ebp], 32                  ; 00000020H
8
  //    mov     ecx, DWORD PTR _b$[ebp]
9
  //    mov     DWORD PTR _a$[ebp], ecx
10
 
11
12
  a = *pb = 48;
13
  // wird zu:
14
  //    mov     edx, DWORD PTR _pb$[ebp]
15
  //    mov     DWORD PTR [edx], 48                     ; 00000030H
16
  //    mov     DWORD PTR _a$[ebp], 48                  ; 00000030H

Bei a=b=32 wird offenbar der aktuelle Wert von b weiterverwendet, also 
deine Variante.

Lustigerweise macht der MS-cl aber aus a=*pb=48 dann doch wieder das 
Gegenteil.

-> ich glaube nicht, daß ich mich in Zukunft auf eines der beiden 
verlassen werde :-)

von Stefan E. (sternst)


Lesenswert?

Klaus Wachtler schrieb:
> Also der gcc schert sich nicht drum, sagst du (welchen Standard auch
> immer du meinst).

Nur dass wir uns nicht missverstehen, ich meinte das nur in Bezug auf 
das "neu einlesen" bei volatile. Das "Ergebnis nicht ursprünglich 
zugewiesener Wert, sondern Inhalt von linker Seite" passt schon.
1
uint8_t x;
2
if (x = 0x100)
ist false.

PS: Zitat stammt aus C99

von (prx) A. K. (prx)


Lesenswert?

Aus
1
volatile char x;
2
void g(void);
3
void f(char y)
4
{
5
        if (x = y) {
6
                g();
7
        }
8
}
macht avr-gcc 4.3.5
1
f:
2
        sts x,r24
3
        lds r24,x
4
        cpse r24,__zero_reg__
5
        rcall g
6
        ret
Passt also. Bei einer Konstanten passt es allerdings nicht:
1
f:
2
        ldi r24,lo8(1)
3
        sts x,r24
4
        rcall g
5
        ret

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
Noch kein Account? Hier anmelden.