用c++中的重新解释强制转换扩展嵌套宏
Expansion of Nested Macros with reinterpret cast in c++
我偶然发现了下面的代码,并发现理解其中的嵌套宏和类型转换非常复杂。
此外,当我试图编译代码时,我遇到了一个错误
需要对以下代码进行解释。
为什么在Motor.h中将BEGIN_STATE_MAP和END_STATE_MAP设置为标签,这对我来说真的很新鲜
提前感谢
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
什么是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
#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:Usersxprk569StateMachinemain.cpp -o objDebugmain.o
In file included from C:Usersxprk569StateMachinemain.cpp:2:0:
C:Usersxprk569StateMachineMotor.h: In member function 'virtual const StateStruct* Motor::GetStateMap()':
C:Usersxprk569StateMachineStateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?)
{ reinterpret_cast<StateFunc>(entry) },
^
C:Usersxprk569StateMachineMotor.h:29:9: note: in expansion of macro 'STATE_MAP_ENTRY'
STATE_MAP_ENTRY(ST_Idle)
^
C:Usersxprk569StateMachineStateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?)
{ reinterpret_cast<StateFunc>(entry) },
^
C:Usersxprk569StateMachineMotor.h:30:9: note: in expansion of macro 'STATE_MAP_ENTRY'
STATE_MAP_ENTRY(ST_Stop)
^
C:Usersxprk569StateMachineStateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?)
{ reinterpret_cast<StateFunc>(entry) },
^
C:Usersxprk569StateMachineMotor.h:31:9: note: in expansion of macro 'STATE_MAP_ENTRY'
STATE_MAP_ENTRY(ST_Start)
^
C:Usersxprk569StateMachineStateMachine.h:40:40: error: invalid use of member (did you forget the '&' ?)
{ reinterpret_cast<StateFunc>(entry) },
^
C:Usersxprk569StateMachineMotor.h:32:9: note: in expansion of macro 'STATE_MAP_ENTRY'
STATE_MAP_ENTRY(ST_ChangeSpeed)
^
C:Usersxprk569StateMachineStateMachine.h:43:39: error: invalid cast from type 'int' to type 'StateFunc {aka void (StateMachine::*)(EventData*)}'
{ reinterpret_cast<StateFunc>(NULL) }
^
C:Usersxprk569StateMachineMotor.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元状态机或boost状态图。
因此,您将很快了解为什么宏在可读C++中不是nos。如果出现错误,则必须展开宏以确定错误所在的位置,而且在大多数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_MAP
和END_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
因此,这组宏将:
- 将作用域设置为
public
- 声明方法
GetStateMap
- 将
StateMap
声明为GetStateMap
的静态本地,它将是StateStruct
的数组 - 在
GetStateMap
方法的第一次调用中,StateMap
将被初始化为包含指向ST_Idle
、ST_Stop
、ST_Start
、ST_ChangeSpeed
和NULL
的reinterpret_cast
到StateFunc
的方法指针 - 定义
GetStateMap
返回StateMap
数组
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- 如何将这个C++哈希表转换为动态扩展和收缩,而不是使用硬设置的最大值
- 在C++中通过零扩展将char强制转换为int
- 将 int 转换为字符串,然后连接另一个变量以创建完整扩展名,然后将其转换为 const_char*
- 如何将 Python 对象转换为 Cython 扩展类型的 std::vector 并返回?
- 超级强大:实时音调转换,时间扩展器不工作
- 在第三方库中扩展隐式转换
- 将 JavaScript Array.slice + 隐式扩展转换为 C++ vector
- 如何将 ZVAL 转换为 PHP 扩展的矢量
- 用c++中的重新解释强制转换扩展嵌套宏
- 通过将基类强制转换为派生类并设置数据来扩展基类
- 具有扩展接口的派生类的集合.如何在没有动态强制转换的情况下访问派生接口
- Makefiles:转换文件扩展名
- 理解扩展和缩小转换C++
- 如何为命名空间和扩展类转换c#到Qt小部件代码(c++)
- 将类型转换扩展到可转换类型的对/元组
- 为什么我不能将超类引用强制转换为同时扩展另一个超类的子类?