2017-07-27 3 views
1

In diesem speziellen Bit des Codes, der Autor tut etwas klug, indem ein Makro verwendet, um Incrementor-Funktionen für alle Mitglieder der Klasse COUNTER zu erstellen.Warum wird das doppelte Pfund an einem Ort benötigt, aber nicht die anderen in diesem Makro?

class COUNTER 
{ 
    public: 
     UINT64 _call; 
     UINT64 _call_indirect; 
     UINT64 _return; 
     UINT64 _syscall; 
     UINT64 _branch; 
     UINT64 _branch_indirect; 

     COUNTER() : _call(0),_call_indirect(0), _return(0), _branch(0), _branch_indirect(0) {} 

     UINT64 Total() 
     { 
      return _call + _call_indirect + _return + _syscall + _branch + _branch_indirect; 
     } 
}; 

COUNTER CountSeen; 
COUNTER CountTaken; 

#define INC(what) VOID inC## what (INT32 taken) { CountSeen. what ++; if(taken) CountTaken. what ++;} 

INC(_call) 
INC(_call_indirect) 
INC(_branch) 
INC(_branch_indirect) 
INC(_syscall) 
INC(_return) 

Ich bin ein wenig verwirrt durch das Makro, obwohl. Warum verwendet der Autor das doppelte Pfund im Funktionsdefinitionsteil des Makros und nicht, wenn es als die Klassenvariable verwendet wird, die inkrementiert wird?

EDIT: ich, dass die Doppel Pfund für Verkettung ist, aber meine Verwirrung kommt von, warum die Doppel Pfund nicht notwendig in der ist und „CountTaken was ++.“ Teile „CountSeen was ++.“ .

+0

Kurze Antwort: Doppel-Pfundzeichen ('##') ist der Präprozessor-Operator für die Verkettung. – DimChtz

Antwort

1

Lassen Sie uns sehen, was das erste Makro (INC(_call)) Aufruf expandiert nach:

VOID inc_call (INT32 taken) { CountSeen. _call ++; if(taken) CountTaken. _call ++;} 

ein bisschen Neuformatierung, erhalten wir:

VOID inc_call (INT32 taken) { 
    CountSeen._call++; 
    if(taken) 
     CountTaken._call++; 
} 

Diese Funktion erklärt, inc_call, dass erhöht CountSeen._call und vielleicht auch CountTaken._call. Da die Variablen nicht ._call genannt werden (was ein ungültiges Token ist, da Sie einen Namen mit einem Punkt nicht starten können), sollte der Punkt nicht auf das Makroargument geklebt werden. Ebenso, da kein gültiges Token ist (es sind zwei Tokens; Sie können keine Pluszeichen in einen Namen einfügen), sollten dort keine Nummernzeichen stehen.

Jedoch ohne das erste ## würde das Ergebnis VOID inc _call (INT32 taken) starten, das auch C++ ungültig ist, weil es zwei Funktionsnamen hätte.

+0

Ahhhh, das macht Sinn. Vielen Dank! –

0

Double Pound ist nur eine Syntax, die zwei Begriffe in der Präprozessorsyntax verketten kann.

Betrachten einfaches Beispiel:

#define foo(x) foo_##x 

void foo_1(); 
void foo_2(); 

... 

foo(1); // this will call foo_1 
+0

Richtig, aber warum wird es nicht in den Teilen "CountSeen. What ++" und "CountTaken. What ++" benötigt? –

+0

@AnthonyCabrera: Weil der Parser 'X.Y' nicht als einzelnes Token liest, sondern als' X', '.' und' Y'. – GManNickG

+0

Weil Sie dort nicht verketten müssen. Sie haben bereits zwei individuelle Token. – SergeyA

1

Die doppelte hash ## wird für Verkettung verwendet. So

INC(_call) 

expandiert nach

VOID inc_call (INT32 taken) { CountSeen. _call ++; if(taken) CountTaken. _call ++;} 

anzumerken, dass CountSeen. _call ++; zu CountSeen._call++; äquivalent ist, aber das ist nicht inc _call entspricht inc_call.

Verwandte Themen