mikrocontroller.net

Forum: PC-Programmierung Programmier Quiz


Autor: Christian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo.

Kleines Quiz:

#define MUL(a, b) a * b
int c = MUL(2+ 3, 2 + 4);

Frage: Was ist das Ergebnis für c?

Was interessant wäre:
Wie lang habt ihr für die richtige Antwort gebraucht?

Gruß
Christian

Autor: ingo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tippe mal auf 30
mfG ingo

Autor: ich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
12

Autor: Patrick (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ergebnis = 6

Autor: Uwe ... (uwegw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist ja nun wirklich einer der bekanntesten Fallstricke bei der 
Verwendung vom Makros...

int c = 2+ 3 * 2 + 4;

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tippe auf 12, denn mit den 30 von ingo sind das dann 42

Autor: Random ... (thorstendb) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
LOL

12

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Christian:
Was kommt hier raus?
#define MUL (a, b) -a*b-
  int a = 1;
  int b = 2;
  int c = MUL(2+ 3, 2 + 4);

Autor: Christian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ergebnis = -6

Autor: Fabian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
12

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fabian schrieb:
> 12

für meine Aufgabe?
Nö.
für das Original?
ja.

Autor: User (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Deswegen schreibt man auch

#define MUL(a, b) (a)*(b)

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian schrieb:
> Ergebnis = -6
ok, das kommt raus, wenn man es laufen lässt.

Die Frage ist natürlich, warum?

Autor: Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Die Frage ist natürlich, warum?
Das ist eine gute Frage! Das originale Rätsel ist ja gerade zu trivial, 
dieses hier ist es deutlich weniger. Man beachte das Leerzeichen hinter 
MUL, ohne compiliert das schon mal nicht. Hab mal geguckt was der 
Präprozessor von GCC da bastelt, kann das aber nicht nachvollziehen, ich 
komme auf -5 oder 1. Sehr komisch...

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Damit hält sich der GCC gar nicht lange auf. Der optimiert das einfach 
weg.

00000088 <main>:

int main(void)
{
  int c = MUL(2+ 3, 2 + 4);

  Initialize();
  88:  f1 df         rcall  .-30       ; 0x6c <Initialize>
  8a:  ff cf         rjmp  .-2        ; 0x8a <main+0x2>

0000008c <SetDAC>:
}

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du Code sehen willst, musst du den Wert natürlich noch verwenden.
Es geht aber nicht darum, den fertigen Wert ausgespuckt zu bekommen,
sondern wie es dazu kommt, also warum zum Schluß ein bestimmter Wert
erscheint.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
User schrieb:

> Deswegen schreibt man auch
> #define MUL(a, b) (a)*(b)

Nur wenn man es immer noch nicht kapiert hat. Denn sonst schriebe man:
  #define MUL(a, b) ((a)*(b))

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
User schrieb:
> Deswegen schreibt man auch
>
> #define MUL(a, b) (a)*(b)

Um genau zu sein, schreibt man sogar
#define MUL(a, b) ((a)*(b))

Das Ergebnis in Klammern zu setzen, verhindert Fehler wie (am Beispiel 
von ADD(a,b) := ((a)+(b))): ADD(1,2)*3. Ohne Klammern wäre dies 
(1)+(2)*3 = 7, mit Klammern korrekterweise ((1)+(2))*3 = 9.

Auch bei MUL sind die Klammern außenrum nötig, da es auch Operatoren mit 
höherer Präzedenz als "*" gibt, nämlich (in C) z.B. unäres "+"/"-", oder 
Adress- und Dereferenzoperator "&" bzw. "*", oder "++"/"--", oder 
Array-Zugriff "[]", oder Funktionsaufruf "()", usw.

Autor: Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab mir das nochmal angeschaut, scheint mit dem oft gelobten / 
verfluchten Kommaoperator und der Operatorenpriorität zutun zu haben...

Aus
c=MUL(2+ 3, 2 + 4);
macht der Präprozessor
c=(a, b) -a*b- (2+ 3, 2 + 4);
.
Wenn man die Variablen "auflöst" gibt das
c=(1, 2) -1*2- (2+ 3, 2 + 4);
was das gleiche Ergebnis wie
c=(2) -1*2- (2 + 4); 
oder "schöner" formatiert
c = 2 - 1 * 2 - (2 + 4);
liefert.

Wenn man die Klammern wegnimmt
c=1, 2 -1*2- 2+ 3, 2 + 4;
compiliert das ganze noch, liefert aber ein falsches Ergebnis (1).

Komische Sache dieses "C"!

Autor: Clown (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei
#define MUL (a, b) -a*b-

int a = 1;
int b = 2;
int c = MUL(2+ 3, 2 + 4);

macht der Präprozessor aus der letzten Zeile
int c = (a, b) -a*b-(2+ 3, 2 + 4);

die wie folgt ausgewertet wird
int c = (a, b) -a*b-(2+ 3, 2 + 4);
// 1:    -  -        ----  -----
//       a  b         5     6
// 2:   ------       ------------
//         b                6
// 3:           ---
//               2
// 4:      ------------------
//         2   - 2 -        6
// 5:      ------------------
//                   -6

1: Zuerst werden die Klammern ausgewertet.
2: Der Komma-Operator bewirkt, daß Wert und Typ
   des Ausdrucks dem letzten Teilausdruck entsprechen.
3: Multiplikation hat die höchste, verbleibende Priorität.
4: Es verbleiben nur noch Subtraktionen.
5: Ergebnis is -6.

Die niedrigste Priorität hat der Zuweisungsoperator, dieser wird als 
letztes berücksichtigt und somit am Ende der Variablen c der Wert -6 
zugewiesen.

Autor: Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Clown
Danke, sehr anschaulich!

Autor: User (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> User schrieb:
>
>> Deswegen schreibt man auch
>> #define MUL(a, b) (a)*(b)
>
> Nur wenn man es immer noch nicht kapiert hat. Denn sonst schriebe man:
>   #define MUL(a, b) ((a)*(b))

Ich hatte noch überlegt, aber dann entschieden, dich nicht damit auch 
noch zu überfordern.

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Wenn du Code sehen willst, musst du den Wert natürlich noch verwenden.
>
> Es geht aber nicht darum, den fertigen Wert ausgespuckt zu bekommen,
>
> sondern wie es dazu kommt, also warum zum Schluß ein bestimmter Wert
>
> erscheint.

Das war mir schon klar. Wenn man die Variable volatile deklariert ist 
das Ergebnis übrigends 12

mfg.

Autor: Christian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zu:
#define MUL (a, b) -a*b-

Die obige define Direktive wird übrigens nicht von allen Compilern
unterstützt.VisualStudio,GCC könnens, spezifische Compiler wie
Cross Compiler oder andere nicht. Meckern tun sie alle bei b-.

Gruß
Christian

Autor: Christian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Klaus
Was kommt hier raus?

#define min(a,b) ( (a < b) ? (a) : (b) )

a = b = 1;
c = min(++a,++b);

c == ???

Gruß
Christian

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieder eher ein Klassiker:
a 3
b 2
c 3

Autor: Christian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wahr lahm, zugegebenermaßen.

Autor: Clown (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Übersehe ich hier etwas? Bei mir gibt
#include <stdio.h>
#include <stdlib.h>

#define min(a,b) ( (a < b) ? (a) : (b) )

int main()
{
  int a, b, c;

  a = b = 1;
  c = min(++a,++b);

  printf("a=%d b=%d c=%d\n", a, b, c);

  return EXIT_SUCCESS;
}

das Ergebnis
> gcc -g -O0 -std=c89 test.c && ./a.out
a=2 b=3 c=3

Zuerst wird die Bedingung (++a < ++b) ausgewertet. Dabei zuerst auf 
beiden Seiten des Vergleichs die Inkrementierung durchgeführt. Die 
Variablen a und b besitzen damit zu dem Zeitpunkt jeweils beide den Wert 
2. Der Vergleich, ob a kleiner b ist, schlägt damit fehl. Dadurch wird 
also der nicht-wahr-Zweig des ternären Operators ausgewertet, also b 
noch einmal inkrementiert. Dieser neue Wert von b, also 3, wird nun der 
Variablen c zugewiesen.

Autor: Christian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Clown hat recht:
b und c haben am Ende 3 -> b==c==3
a wird nur einmal inkrementiert-> also a==2

Gruß
Christian

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, sorry - Schreibfehler von mir

Gefragt war ja nur nach c, insofern ist der Fehler vielleicht 
verzeihlich :-)

Autor: sebastians (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> c = min(++a,++b);
undefiniert. Zweimal Seiteneffekt mit der gleichen Variablen in einem 
Ausdruck.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sebastians schrieb:

> undefiniert. Zweimal Seiteneffekt mit der gleichen Variablen in einem
> Ausdruck.

Nein. Das ? in ?: ist ein sequence point.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian schrieb:
> Clown hat recht:
> b und c haben am Ende 3 -> b==c==3
> a wird nur einmal inkrementiert-> also a==2

Wobei ein fieser Nebenschauplatz an der Situation darin besteht, dass 
auch der Fall möglich ist, dass hinten nach a gleich c ist und b nur 
einmal inkrementiert wird. Je nach den konkreten Werten für a und b

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja, aber a und b waren doch gegeben.

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.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

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