Wilhelm M. schrieb:> Und ich wage zu vermuten, dass das, was der TO machen will, auch als C++> übersetzbar wäre ...
Und wenn es als Python oder Haskell oder BrainFuck übersetzbar wäre:
Spielt das eine Rolle?
Es geht um C11.
Und die Applikation des TO besteht vermutlich aus mehr als den nur
duzend Zeilen des Testfalls.
Johann L. schrieb:> Wilhelm M. schrieb:>> Und ich wage zu vermuten, dass das, was der TO machen will, auch als C++>> übersetzbar wäre ...>> Und wenn es als Python oder Haskell oder BrainFuck übersetzbar wäre:> Spielt das eine Rolle?>> Es geht um C11.>> Und die Applikation des TO besteht vermutlich aus mehr als den nur> duzend Zeilen des Testfalls.
Ich bin der Meinung, dass man Fragen auch durchaus einmal unter einem
anderen Gesichtspunkt als dem des Fragenden beantworten darf, denn der
ist oftmals in seinem eigenen Gedankengebäude gefangen. In diesem Sinne
darf der Hinweis auf eine eng verwandte Sprache erlaubt sein, in der
es gerade für das konkrete Problem des Fragenden einen Mechanismus gibt:
hier das template-System.
Wilhelm M. schrieb:> Johann L. schrieb:>> Wilhelm M. schrieb:>>> Und ich wage zu vermuten, dass das, was der TO machen will, auch als C++>>> übersetzbar wäre ...>>>> Und wenn es als Python oder Haskell oder BrainFuck übersetzbar wäre:>> Spielt das eine Rolle?>>>> Es geht um C11.>>>> Und die Applikation des TO besteht vermutlich aus mehr als den nur>> duzend Zeilen des Testfalls.>> Ich bin der Meinung, dass man Fragen auch durchaus einmal unter einem> anderen Gesichtspunkt als dem des Fragenden beantworten darf, denn der
Eine C++ Diskussion ist keine Beantwortung einer Frage zu C11.
> ist oftmals in seinem eigenen Gedankengebäude gefangen.
Ich habe eher den Eindruck, das Problem ist das manche in C++ gefangen
sind, und zu allem ihren C++ Senf geben (müssen?).
> In diesem Sinne darf der Hinweis auf eine eng verwandte Sprache
Okay, also auch Objective-C und B und D...
Und in deinem eigenen "Fütter"-Thread wirst du garstig, wenn jemand mehr
als einen Link postet.
> erlaubt sein,
Johann L. schrieb:> Okay, also auch Objective-C und B und D...
Warum nicht, it's up to you ...
>> Und in deinem eigenen "Fütter"-Thread wirst du garstig, wenn jemand mehr> als einen Link postet.
Und der ist genau zu diesem Zweck - Sammlung, kein Diskussion - eröffnet
worden.
Wenn der TO sich hier zu Wort meldet, und keine Hinweise mehr auf etwas
anderes als C11 haben möchte, dann halte ich ich gerne zurück ;-)
Also, zum Ausgangsposting: offenbar werden die Ausdrücke nicht wie ein
Switch-Case im Programm abgearbeitet, sondern von innen nach außen
expandiert. Das wäre ja bei einem Parser auch zu erwarten.
Wenn man das jetzt macht, also erstmal alle inneren Makros abarbeitet,
dann geht das für die Zeile mit den uint32_t glatt, aber bei der
int32_t-Zeile scheitert das, weil b eben kein int32_t ist.
Deswegen geht auch die zweite Variante, weil da kein inneres Generic
ist, was beim Expandieren scheitern würde.
Tester schrieb:> Aber mit der Erklärung komme ich nicht ganz klar.
Also im Programm wird ein verschachtelter Switch-Case ja von oben nach
unten durchlaufen. Wenn der äußere case zutrifft und man da noch innere
Switch-Case drinnen hat, wird nur der durchlaufen, wo der äußere schon
paßt.
1
int outer = 1, inner = 2, result = 0;
2
3
switch (outer)
4
{
5
case 1:
6
switch (inner)
7
{
8
case 1:
9
result = 1;
10
break;
11
case 2:
12
result = 2;
13
break;
14
}
15
break;
16
case 2:
17
switch (inner)
18
{
19
case 1:
20
result = 3;
21
break;
22
case 2:
23
result = 4;
24
break;
25
}
26
break;
27
}
Hier geht es oben los, der Programmfluß geht im oberen "case 1" rein und
betritt das inner switch-case. Da gibt's dann den Match bei case 2, und
result wird auf 2 gesetzt. Das ist imperative Programmierung,
sequentiell und Schritt für Schritt.
Das Verführerische bei Deinen Makros ist jetzt, daß Generics eine Art
einfaches switch-case für Types sind. Das ist aber nur rein logisch
gesehen so, aber nicht von der Umsetzung. Es ist ein Makro, damit gibt
es da keinen Programmablauf. Expandiert wird schließlich im
Präprozessor. Man hat hier vielmehr verschachtelte Ausdrücke.
Ein Ausdruck wie
2 * ((3 + 4) / (5 + 6))
wird nicht von links nach rechts ausgewertet in dem Sinne, sondern von
innen nach außen. Es wird also erstmal das Ergebnis der innersten
Klammern bestimmt, dann das der äußeren, und zuletzt multipliziert.
Und genau das haste bei den Makros auch - keinen Programmablauf, sondern
die Auswertung geklammerter Ausdrücke.
Johann L. schrieb:> _Generic ist kein Makro. Es ist ein neues Schlüselwort ab C11.
Naja in dem Kontext mit den defines meinte ich halt. Jedenfalls sind es
Ausdrücke, keine Abläufe.
Btw., die Nummer mit dem "default: NULL" ist ein quick&dirty-Hack, der
nur zur Verdeutlichung des Prinzips gedacht ist und nicht zur Übernahme
in eine reale Anwendung. Die Konsequenz wäre nämlich ein Programmabsturz
(Segfault), wenn a und b nicht beide int32_t oder beide uint32_t sind.
Das Problem an der ganzen Sache ist, dass der C-Präprozessor (CPP) ein
nicht interaktiver Editor ist. Der Compiler übersetzt also nicht das,
was man geschrieben hat, sondern das, was der CPP daraus gemacht hat.
Im Beispiel:
und damit auch sofort klar, warum das ursprüngliche Macro nicht gehen
kann (s.a. alte Regel: schreibe nie CPP-Macros, die wie Funktionen
aussehen ...)
Der zweite Fallstrick am _Generic ist, das der default-Teil ebenfalls
instanziiert wird. Dort muss also ein wohlgeformter Ausdruck stehen.
Deswegen habe ich das Beispiel oben so formuliert, dass dort die Symbole
bad1, 2, 3 auftauchen. Sind die nicht deklariert, gibt es bei der
Auswertung des _Generic ein Fehler ...