簡體   English   中英

使用C ++中的重新解釋擴展嵌套宏

[英]Expansion of Nested Macros with reinterpret cast in c++

我偶然發現了以下代碼,並發現它很難理解嵌套宏並在其中進行類型轉換。

另外,當我嘗試編譯代碼時,我遇到了一個錯誤

將需要以下代碼的說明。

為什么在Motor.h中將BEGIN_STATE_MAP和END_STATE_MAP設置為標簽,這對我來說真的很新

提前致謝

電機

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

什么是BEGIN_STATE_MAP和END_STATE_MAP,我發現這個定義確實很新,BEGIN_STATE_MAP和END_STATE_MAP是下面的頭文件中定義的宏。

狀態機

#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

當我嘗試編譯上面的代碼時,下面是遇到的錯誤

錯誤

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

可以請解釋一下為什么在Motor.h中以這種方式編寫宏,為什么在StateMachine.h中這樣聲明宏,以及為什么引發錯誤?

提前致謝

看起來這段代碼取決於一些非標准的編譯器擴展/錯誤。

要使其編譯(不知道它是否真的可以工作),您需要用完全限定的成員函數指針替換函數名稱:

例如

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

之后,您需要找出一種方法來克服不合格的鑄件:

/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'

此演員表完全是非法的。 如果我是我,我會把代碼扔進垃圾桶並重寫-或使用經過驗證的狀態機框架,如boost meta state machine或boost statechart。

因此,您正在迅速學習為什么在可讀的C ++中宏不能被拒絕。 如果遇到錯誤,則必須擴展宏以識別錯誤的位置,並且您也無法在大多數IDE中對其進行調試。

不管怎么說,讓我們開始擴展,它們都是一樣的錯誤,所以我們只看第一個:

C:\\ Users \\ xprk569 \\ StateMachine \\ Motor.h:29:9:注意:在宏STATE_MAP_ENTRY擴展中
STATE_MAP_ENTRY(ST_Idle)
C:\\ Users \\ xprk569 \\ StateMachine \\ StateMachine.h:40:40:錯誤:成員使用無效(您是否忘記了& ?)
{ reinterpret_cast<StateFunc>(entry) },

因此,這是在抱怨第29行: STATE_MAP_ENTRY(ST_Idle)因此,讓我們擴展一下:

{ reinterpret_cast<StateFunc>(entry) },

顯然,在BEGIN_STATE_MAPEND_STATE_MAP的作用域之外,這都是很糟糕的語法,因此在調試許多宏時,您還必須查看作用域宏……有時可能並沒有清楚地命名或描述它們,但是讓我們完成定義行,我們首先遇到錯誤。 我們要投射到的StateFunc是什么?

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

它是指向成員函數的指針,該成員函數返回void並接受EventData * 而且鬧鍾應該響了。 你不能那樣做! ST_Idle的格式為: void (StateMachine::*)()因此無法轉換為void (StateMachine::*StateFunc)(EventData *) 對於傳遞給宏的所有函數,這都是相同的問題,它們都不返回void並接受EventData* ,因此,即使您修復了語法,這些reinterpret_cast始終將返回指向無效調用方法的指針,意味着整個“宏”塊在最佳情況下毫無意義,而在最壞的情況下則有毒。 在當前狀態下,您也可以不使用這些宏,也可以使用以下宏:

BEGIN_STATE_MAP
END_STATE_MAP

但是,如果您打算將方法聲明更改為類似以下內容:

void ST_Idle(EventData*);

然后,您需要使用以下語法:

STATE_MAP_ENTRY(&Motor::ST_Idle)

如果您對方法指針不滿意,它們將非常復雜。 我在這里輸入了一個簡單的示例: http : //ideone.com/nL0HnQ隨時提出問題。

編輯:

在這里擴展宏,我們將得到:

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

因此,這組宏將:

  1. 將范圍設為public
  2. 聲明方法GetStateMap
  3. 聲明StateMap靜態地StateMap GetStateMap本地,它將是StateStruct的數組
  4. 在首次調用GetStateMap方法StateMap將初始化ST_Idle ,以包含指向ST_IdleST_StopST_StartST_ChangeSpeedNULL方法指針,以及指向StateFuncreinterpret_cast
  5. 定義GetStateMap以返回StateMap數組

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM