2016-04-14 3 views
0

Ich stolperte über den folgenden Code und fand es wirklich komplex, das verschachtelte Makro zu verstehen und Casting darin zu schreiben.Erweiterung von verschachtelten Makros mit Uminterpret in C++ umgewandelt

Auch wenn ich versuche, den Code zu kompilieren, ich habe einen Fehler

Brauchte eine explanantion des Code unten gestoßen.

warum BEGIN_STATE_MAP und END_STATE_MAP als Etiketten in Motor.h gesetzt, Das ist mir wirklich neu ist

Vielen Dank im Voraus

Motor.h

// the Motor state machine class 
class Motor : public StateMachine 
{ 
public: 
    Motor() : StateMachine(ST_MAX_STATES) {} 

    // external events taken by this state machine 
    void Halt(); 
    void SetSpeed(MotorData*); 
private: 
    // state machine state functions 
    void ST_Idle(); 
    void ST_Stop(); 
    void ST_Start(MotorData*); 
    void ST_ChangeSpeed(MotorData*); 

    // state map to define state function order 
    BEGIN_STATE_MAP 
     STATE_MAP_ENTRY(ST_Idle) 
     STATE_MAP_ENTRY(ST_Stop) 
     STATE_MAP_ENTRY(ST_Start) 
     STATE_MAP_ENTRY(ST_ChangeSpeed) 
    END_STATE_MAP 

    // state enumeration order must match the order of state 
    // method entries in the state map 
    enum E_States { 
     ST_IDLE = 0, 
     ST_STOP, 
     ST_START, 
     ST_CHANGE_SPEED, 
     ST_MAX_STATES 
    }; 
}; 
#endif //MOTOR_H 

was sind BEGIN_STATE_MAP und END_STATE_MAP, Diese definition ich fand ich wirklich neu, BEGIN_STATE_MAP und END_STATE_MAP sind die Makros in der folgenden Header-Datei definiert.

StateMachine.h

#ifndef STATE_MACHINE_H 
#define STATE_MACHINE_H 
#include <stdio.h> 
#include "EventData.h" 

struct StateStruct; 

// base class for state machines 
class StateMachine 
{ 
public: 
    StateMachine(int maxStates); 
    virtual ~StateMachine() {} 
protected: 
    enum { EVENT_IGNORED = 0xFE, CANNOT_HAPPEN }; 
    unsigned char currentState; 
    void ExternalEvent(unsigned char, EventData* = NULL); 
    void InternalEvent(unsigned char, EventData* = NULL); 
    virtual const StateStruct* GetStateMap() = 0; 
private: 
    const int _maxStates; 
    bool _eventGenerated; 
    EventData* _pEventData; 
    void StateEngine(void); 
}; 

typedef void (StateMachine::*StateFunc)(EventData *); 
struct StateStruct 
{ 
    StateFunc pStateFunc; 
}; 

#define BEGIN_STATE_MAP \ 
public:\ 
const StateStruct* GetStateMap() {\ 
    static const StateStruct StateMap[] = { 

#define STATE_MAP_ENTRY(entry)\ 
    { reinterpret_cast<StateFunc>(entry) }, 

#define END_STATE_MAP \ 
    { reinterpret_cast<StateFunc>(NULL) }\ 
    }; \ 
    return &StateMap[0]; } 

#define BEGIN_TRANSITION_MAP \ 
    static const unsigned char TRANSITIONS[] = {\ 

#define TRANSITION_MAP_ENTRY(entry)\ 
    entry, 

#define END_TRANSITION_MAP(data) \ 
    0 };\ 
    ExternalEvent(TRANSITIONS[currentState], data); 

#endif 

EventData.h

#ifndef EVENT_DATA_H 
#define EVENT_DATA_H 

class EventData 
{ 
public: 
    virtual ~EventData() {}; 
}; 
#endif //EVENT_DATA_H 

Während ich den Code zu kompilieren above.Below versucht, ist der Fehler, der

Fehler

-------------- Build: Debug in StateMachine (compiler: GNU GCC Compiler)--------------- 

mingw32-g++.exe -Wall -fexceptions -g -pedantic -Wzero-as-null-pointer-constant -std=c++0x -Wextra -Wall -c C:\Users\xprk569\StateMachine\main.cpp -o obj\Debug\main.o 
In file included from C:\Users\xprk569\StateMachine\main.cpp:2:0: 
C:\Users\xprk569\StateMachine\Motor.h: In member function 'virtual const StateStruct* Motor::GetStateMap()': 
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?) 
    { reinterpret_cast<StateFunc>(entry) }, 
             ^
C:\Users\xprk569\StateMachine\Motor.h:29:9: note: in expansion of macro 'STATE_MAP_ENTRY' 
     STATE_MAP_ENTRY(ST_Idle) 
     ^
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?) 
    { reinterpret_cast<StateFunc>(entry) }, 
             ^
C:\Users\xprk569\StateMachine\Motor.h:30:9: note: in expansion of macro 'STATE_MAP_ENTRY' 
     STATE_MAP_ENTRY(ST_Stop) 
     ^
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?) 
    { reinterpret_cast<StateFunc>(entry) }, 
             ^
C:\Users\xprk569\StateMachine\Motor.h:31:9: note: in expansion of macro 'STATE_MAP_ENTRY' 
     STATE_MAP_ENTRY(ST_Start) 
     ^
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?) 
    { reinterpret_cast<StateFunc>(entry) }, 
             ^
C:\Users\xprk569\StateMachine\Motor.h:32:9: note: in expansion of macro 'STATE_MAP_ENTRY' 
     STATE_MAP_ENTRY(ST_ChangeSpeed) 
     ^
C:\Users\xprk569\StateMachine\StateMachine.h:43:39: error: invalid cast from type 'int' to type 'StateFunc {aka void (StateMachine::*)(EventData*)}' 
    { reinterpret_cast<StateFunc>(NULL) }\ 
            ^
C:\Users\xprk569\StateMachine\Motor.h:33:5: note: in expansion of macro 'END_STATE_MAP' 
    END_STATE_MAP 
    ^
Process terminated with status 1 (0 minute(s), 0 second(s)) 
5 error(s), 0 warning(s) (0 minute(s), 0 second(s)) 
aufgetreten

Können einige bitte erklären, warum das Makro in Motor.h geschrieben wird, Warum wird es so in StateMachine.h und wie erklärt, warum wird der Fehler ausgelöst?

Vielen Dank im Voraus

+0

"was sind BEGIN_STATE_MAP und END_STATE_MAP" - „sind die definierten Makros in der sein niedrige Header-Datei. " Ich nehme an, du hast dich selbst geantwortet. –

+1

Vermeiden Sie Makros (Kopieren Sie nicht die alten MFC) –

+0

Ja, das ist richtig. Sie sind Makros, können aber nicht als Funktionen geschrieben werden, um den Code verständlich zu machen. Meine Frage war, warum sind sie als Labels in Motor.h gesetzt, wird die Frage bearbeiten :) – user2256825

Antwort

1

Es ist wie dieser Code sieht, hängt von einigen Nicht-Standard-Compiler-Erweiterungen/Fehler.

Um es zu kompilieren Sie (keine Ahnung, ob es tatsächlich funktioniert) müssen die Funktionsnamen mit voller kundigen Mitglied Funktionszeigern ersetzen:

z.B.

BEGIN_STATE_MAP 
    STATE_MAP_ENTRY(&Motor::ST_Idle) 
    STATE_MAP_ENTRY(&Motor::ST_Stop) 
    STATE_MAP_ENTRY(&Motor::ST_Start) 
    STATE_MAP_ENTRY(&Motor::ST_ChangeSpeed) 
END_STATE_MAP 

Danach müssen Sie einen Weg, um herauszufinden, die nicht konforme Guss zu überwinden:

/tmp/gcc-explorer-compiler116314-75-1uiyu0/example.cpp: In member function 'virtual const StateStruct* Motor::GetStateMap()': 
44 : error: invalid cast from type 'long int' to type 'StateFunc {aka void (StateMachine::*)(EventData*)}' 
{ reinterpret_cast<StateFunc>(NULL) }\ 
^ 
83 : note: in expansion of macro 'END_STATE_MAP' 

Diese Umwandlung völlig illegal ist. Wenn ich Sie wäre, würde ich den Code in den Papierkorb werfen und neu schreiben - oder ein bewährtes State-Machine-Framework wie Boost-State-Machine oder Boost-Statechart verwenden.

+0

Warum ist STATE_MAP_ENTRY (..) zwischen BEGIN_STATE_MAP und END_STATE_MAP, ich verstehe, es ist Makro, aber warum ist es so definiert? – user2256825

+0

@ user2256825 Ich werde vermuten, dass es vor Jahren unter Visual Studio 5 oder 6 geschrieben wurde? Damals war C++ eine sehr unterentwickelte Sprache und Implementierer mussten auf böse Tricks zurückgreifen. –

0

So lernen Sie schnell, warum Makros in lesbaren C++ keine Nos sind. Wenn Sie einen Fehler erhalten, müssen Sie das Makro erweitern, um festzustellen, wo sich der Fehler befindet. Außerdem können Sie in den meisten IDEs nicht in den Fehler debuggen.

Wie dem auch sei, das lässt auf die expandierende erhalten, sagte, ihr alle den gleichen Fehler, so dass wir bei der ersten Blick einfach werden:

C:\Users\xprk569\StateMachine\Motor.h:29:9: note: in expansion of macro STATE_MAP_ENTRY
STATE_MAP_ENTRY(ST_Idle)
C:\Users\xprk569\StateMachine\StateMachine.h:40:40: error: invalid use of member (did you forget the & ?)
{ reinterpret_cast<StateFunc>(entry) },

Also diese beschwert sich über Linie 29: STATE_MAP_ENTRY(ST_Idle) lässt, dass so erweitern:

{ reinterpret_cast<StateFunc>(entry) }, 

Offensichtlich ist diese schlechte Syntax alle zusammen außerhalb der Scoping von BEGIN_STATE_MAP und END_STATE_MAP, so in vielen Makros debuggen Sie auch an den Scoping-Makros aussehen müsste ... manchmal können sie nicht eindeutig benannt werden oder umreißen d leider, aber lasst uns die Zeile definieren, auf der wir den Fehler zuerst bekommen haben. Was ist das StateFunc wir versuchen zu werfen?

typedef void (StateMachine::*StateFunc)(EventData *); 

Es ist ein Zeiger auf eine Elementfunktion, die ein void zurückgibt und akzeptiert ein EventData *. Und Alarmglocken sollten ausgehen. Das kannst du nicht tun! ST_Idle hat das Format: void (StateMachine::*)(), so dass Sie nicht auf void (StateMachine::*StateFunc)(EventData *) zu werfen. Dies ist das gleiche Problem für alle Ihre Funktionen in die Makros übergeben keine von ihnen eine void zurückgeben und eine EventData* nehmen, so dass selbst wenn Sie die Syntax beheben, diese reinterpret_cast s immer einen Zeiger auf eine Methode zurückgeben, die ungültig zu nennen ist, bedeutet Dieser ganze Makroblock ist im besten Fall sinnlos und im schlimmsten Fall giftig. Im aktuellen Zustand können auch verwenden Sie einfach keines dieser Makros oder wenn Sie die Methode definieren, müssen nur tun:

BEGIN_STATE_MAP 
END_STATE_MAP 

Aber wenn Sie Ihre Methode Erklärungen etwas ändern wollen mehr wie:

void ST_Idle(EventData*); 

Dann müssten Sie diese Syntax verwenden:

STATE_MAP_ENTRY(&Motor::ST_Idle) 

Wenn Sie nicht nach unten mit den Methodenzeiger sind sind sie ziemlich komplex. Ich habe hier ein schnelles Beispiel eingegeben: http://ideone.com/nL0HnQ Fühlen Sie sich frei, mit Fragen zu kommentieren.

EDIT:

Um die Makros zu erweitern hier werden wir erhalten:

public: // BEGIN_STATE_MAP 
const StateStruct* GetStateMap() { // BEGIN_STATE_MAP 
    static const StateStruct StateMap[] = { // BEGIN_STATE_MAP 
    { reinterpret_cast<StateFunc>(ST_Idle) } // STATE_MAP_ENTRY(ST_Idle) 
    { reinterpret_cast<StateFunc>(ST_Stop) } // STATE_MAP_ENTRY(ST_Stop) 
    { reinterpret_cast<StateFunc>(ST_Start) } // STATE_MAP_ENTRY(ST_Start) 
    { reinterpret_cast<StateFunc>(ST_ChangeSpeed) } // STATE_MAP_ENTRY(ST_ChangeSpeed) 
    { reinterpret_cast<StateFunc>(NULL) } // END_STATE_MAP 
    }; // END_STATE_MAP 
    return &StateMap[0]; } // END_STATE_MAP 

Also dieser Satz von Makros:

  1. Stellen Sie den Umfang public
  2. Deklarieren Sie die Methode GetStateMap
  3. Deklarieren StateMap statisch GetStateMap lokale, wird es ein Array von StateStruct s
  4. Beim ersten Aufruf der GetStateMap Methode StateMap wird initialisiert enthalten Methodenzeiger auf ST_Idle, ST_Stop, ST_Start, ST_ChangeSpeed und NULLreinterpret_cast zu StateFunc sein s
  5. definieren GetStateMap zurückzukehren, um die StateMap Array
+0

Danke, aber ich habe nicht verstanden, was diese Syntax BEGIN_STATE_MAP STATE_MAP_ENTRY (& Motor :: ST_Idle) STATE_MAP_ENTRY (& Motor :: ST_Stop) STATE_MAP_ENTRY (& Motor :: ST_Start) STATE_MAP_ENTRY (& Motor :: ST_ChangeSpeed) END_STATE_MAP. Ich verstehe Funktionszeiger, aber dint Benutzer stehen, was die obigen 5 Zeilen, was Anfang und Ende tun, warum sind die Funktion ptrs innerhalb beginnen und enden, warum können sie nicht draußen sein, wollte nur die Syntax von oben 5 Zeilen zu verstehen – user2256825

+0

@ user2256825 Ich habe bearbeitet, um zu erklären, was diese Makros tun, indem Sie sie erweitern. Hoffentlich wird die Tatsache, dass Sie eine Frage auf http://www.stackoverflow.com stellen müssen, um die Makros zu verstehen, Sie davon abhalten, sie zu verwenden, weil, wie bereits mehrfach erwähnt wurde, Macros schwer zu lesen, zu verwenden, zu pflegen und zu sein erklären. –