Programmier Quiz

Gast
>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...
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>:
}
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.
Gast
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.
Gast
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"!
Gast
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.
Gast
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.
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.
Gast
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
Gast
Ü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.
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

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 15 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.