Forum: PC-Programmierung Programmier Quiz


von Christian (Gast)


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

von ingo (Gast)


Lesenswert?

Tippe mal auf 30
mfG ingo

von ich (Gast)


Lesenswert?

12

von Patrick (Gast)


Lesenswert?

Ergebnis = 6

von Uwe .. (uwegw)


Lesenswert?

Das ist ja nun wirklich einer der bekanntesten Fallstricke bei der 
Verwendung vom Makros...

int c = 2+ 3 * 2 + 4;

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Tippe auf 12, denn mit den 30 von ingo sind das dann 42

von Random .. (thorstendb) Benutzerseite


Lesenswert?

LOL

12

von Klaus W. (mfgkw)


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

von Christian (Gast)


Lesenswert?

Ergebnis = -6

von Fabian (Gast)


Lesenswert?

12

von Klaus W. (mfgkw)


Lesenswert?

Fabian schrieb:
> 12

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

von User (Gast)


Lesenswert?

Deswegen schreibt man auch

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

von Klaus W. (mfgkw)


Lesenswert?

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

Die Frage ist natürlich, warum?

von Anfänger (Gast)


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

von Thomas E. (thomase)


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>:
}

von Klaus W. (mfgkw)


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.

von (prx) A. K. (prx)


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

von Sebastian (Gast)


Lesenswert?

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

Um genau zu sein, schreibt man sogar
1
#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.

von Anfänger (Gast)


Lesenswert?

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

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

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

Komische Sache dieses "C"!

von Clown (Gast)


Lesenswert?

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

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

die wie folgt ausgewertet wird
1
int c = (a, b) -a*b-(2+ 3, 2 + 4);
2
// 1:    -  -        ----  -----
3
//       a  b         5     6
4
// 2:   ------       ------------
5
//         b                6
6
// 3:           ---
7
//               2
8
// 4:      ------------------
9
//         2   - 2 -        6
10
// 5:      ------------------
11
//                   -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.

von Anfänger (Gast)


Lesenswert?

@Clown
Danke, sehr anschaulich!

von User (Gast)


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.

von Thomas E. (thomase)


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.

von Christian (Gast)


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

von Christian (Gast)


Lesenswert?

@Klaus
Was kommt hier raus?

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

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

c == ???

Gruß
Christian

von Klaus W. (mfgkw)


Lesenswert?

Wieder eher ein Klassiker:
a 3
b 2
c 3

von Christian (Gast)


Lesenswert?

Wahr lahm, zugegebenermaßen.

von Clown (Gast)


Lesenswert?

Übersehe ich hier etwas? Bei mir gibt
1
#include <stdio.h>
2
#include <stdlib.h>
3
4
#define min(a,b) ( (a < b) ? (a) : (b) )
5
6
int main()
7
{
8
  int a, b, c;
9
10
  a = b = 1;
11
  c = min(++a,++b);
12
13
  printf("a=%d b=%d c=%d\n", a, b, c);
14
15
  return EXIT_SUCCESS;
16
}

das Ergebnis
1
> gcc -g -O0 -std=c89 test.c && ./a.out
2
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.

von Christian (Gast)


Lesenswert?

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

Gruß
Christian

von Klaus W. (mfgkw)


Lesenswert?

Ja, sorry - Schreibfehler von mir

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

von sebastians (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

sebastians schrieb:

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

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

von Karl H. (kbuchegg)


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

von Klaus W. (mfgkw)


Lesenswert?

ja, aber a und b waren doch gegeben.

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.