简体   繁体   English

使用C ++中的重新解释扩展嵌套宏

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

I stumbled across the below code and really found it complex to understand the nested macro and type casting in it. 我偶然发现了以下代码,并发现它很难理解嵌套宏并在其中进行类型转换。

Also when i tried to compile the code , i have encountered an error 另外,当我尝试编译代码时,我遇到了一个错误

Would need an explanantion of the below code. 将需要以下代码的说明。

why BEGIN_STATE_MAP and END_STATE_MAP set as labels in Motor.h , This is really new to me 为什么在Motor.h中将BEGIN_STATE_MAP和END_STATE_MAP设置为标签,这对我来说真的很新

Thanks in advance 提前致谢

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

what are BEGIN_STATE_MAP and END_STATE_MAP, This definition i found i really new, BEGIN_STATE_MAP and END_STATE_MAP are the Macros defined in the below header file. 什么是BEGIN_STATE_MAP和END_STATE_MAP,我发现这个定义确实很新,BEGIN_STATE_MAP和END_STATE_MAP是下面的头文件中定义的宏。

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 EventData.h

#ifndef EVENT_DATA_H
#define EVENT_DATA_H

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

While i tried to compile the code above.Below is the error that was encountered 当我尝试编译上面的代码时,下面是遇到的错误

Error 错误

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

Can some please explain why is the macro written that way in Motor.h, why is it declared like that in StateMachine.h and why is the error being thrown ? 可以请解释一下为什么在Motor.h中以这种方式编写宏,为什么在StateMachine.h中这样声明宏,以及为什么引发错误?

Thanks in Advance 提前致谢

It looks like this code depends on some nonstandard compiler extensions/errors. 看起来这段代码取决于一些非标准的编译器扩展/错误。

To get it to compile (no idea if it will actually work) you need to replace the function names with full qualified member function pointers: 要使其编译(不知道它是否真的可以工作),您需要用完全限定的成员函数指针替换函数名称:

eg 例如

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

After that, you need to figure out a way to overcome the non-conforming cast: 之后,您需要找出一种方法来克服不合格的铸件:

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

This cast is completely illegal. 此演员表完全是非法的。 If I were you I would throw the code in the trash and rewrite - or use a proven state machine framework like boost meta state machine or boost statechart. 如果我是我,我会把代码扔进垃圾桶并重写-或使用经过验证的状态机框架,如boost meta state machine或boost statechart。

So you're quickly learning why Macros are no-nos in readable C++. 因此,您正在迅速学习为什么在可读的C ++中宏不能被拒绝。 If you get an error, you must expand the macro out to identify where the error is, also you cannot debug into them in most IDEs. 如果遇到错误,则必须扩展宏以识别错误的位置,并且您也无法在大多数IDE中对其进行调试。

Anyway that said lets get to the expanding, their all the same error so we'll just look at the first one: 不管怎么说,让我们开始扩展,它们都是一样的错误,所以我们只看第一个:

C:\\Users\\xprk569\\StateMachine\\Motor.h:29:9: note: in expansion of macro STATE_MAP_ENTRY C:\\ Users \\ xprk569 \\ StateMachine \\ Motor.h:29:9:注意:在宏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 & ?) C:\\ Users \\ xprk569 \\ StateMachine \\ StateMachine.h:40:40:错误:成员使用无效(您是否忘记了& ?)
{ reinterpret_cast<StateFunc>(entry) },

So this is complaining about line 29: STATE_MAP_ENTRY(ST_Idle) So lets expand that: 因此,这是在抱怨第29行: STATE_MAP_ENTRY(ST_Idle)因此,让我们扩展一下:

{ reinterpret_cast<StateFunc>(entry) },

Obviously this is bad syntax all together outside the scoping of BEGIN_STATE_MAP and END_STATE_MAP , so in debugging many Macros you'd also have to look at the scoping macros... sometimes they may not be clearly named or delineated unfortunately, but let's finish defining the line we got the error on first. 显然,在BEGIN_STATE_MAPEND_STATE_MAP的作用域之外,这都是很糟糕的语法,因此在调试许多宏时,您还必须查看作用域宏……有时可能并没有清楚地命名或描述它们,但是让我们完成定义行,我们首先遇到错误。 What is this StateFunc we're trying to cast to? 我们要投射到的StateFunc是什么?

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

It's a pointer to a member function which returns a void and accepts an EventData * . 它是指向成员函数的指针,该成员函数返回void并接受EventData * And alarm bells should be going off. 而且闹钟应该响了。 You cannot cast to that! 你不能那样做! ST_Idle is of the format: void (StateMachine::*)() so you cannot cast to void (StateMachine::*StateFunc)(EventData *) . ST_Idle的格式为: void (StateMachine::*)()因此无法转换为void (StateMachine::*StateFunc)(EventData *) This is the same problem for all your functions passed into the macros none of them return a void and take an EventData* , so even if you fix the syntax, these reinterpret_cast s will always return a pointer to a method which is invalid to call, meaning this entire block of Macros is pointless at best and toxic at worst. 对于传递给宏的所有函数,这都是相同的问题,它们都不返回void并接受EventData* ,因此,即使您修复了语法,这些reinterpret_cast始终将返回指向无效调用方法的指针,意味着整个“宏”块在最佳情况下毫无意义,而在最坏的情况下则有毒。 In the current state you may just as well use none of these Macros or if you need to define the method just do: 在当前状态下,您也可以不使用这些宏,也可以使用以下宏:

BEGIN_STATE_MAP
END_STATE_MAP

But if you were going to change your method declarations to something more like: 但是,如果您打算将方法声明更改为类似以下内容:

void ST_Idle(EventData*);

Then you'd need to use this syntax: 然后,您需要使用以下语法:

STATE_MAP_ENTRY(&Motor::ST_Idle)

If you're not down with the method pointers they are quite complex. 如果您对方法指针不满意,它们将非常复杂。 I've typed up a quick example here: http://ideone.com/nL0HnQ Feel free to comment with questions. 我在这里输入了一个简单的示例: http : //ideone.com/nL0HnQ随时提出问题。

EDIT: 编辑:

To expand the Macros here we'll get: 在这里扩展宏,我们将得到:

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

So this set of macros will: 因此,这组宏将:

  1. Set the scope to public 将范围设为public
  2. Declare the method GetStateMap 声明方法GetStateMap
  3. Declare StateMap statically local to GetStateMap , it will be an array of StateStruct s 声明StateMap静态地StateMap GetStateMap本地,它将是StateStruct的数组
  4. On the first call of the GetStateMap method StateMap will be initialized to contain method pointers to ST_Idle , ST_Stop , ST_Start , ST_ChangeSpeed , and NULL reinterpret_cast to StateFunc s 在首次调用GetStateMap方法StateMap将初始化ST_Idle ,以包含指向ST_IdleST_StopST_StartST_ChangeSpeedNULL方法指针,以及指向StateFuncreinterpret_cast
  5. Define GetStateMap to return the StateMap array 定义GetStateMap以返回StateMap数组

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM