I have this macro from someone's code:
#define Q_DEF_PROTOTYPE( Type, Name ) Type (*Name)
#define COPY_FP( pDest, pSrc ) (*((void**)(&(pDest)))) = ((void*)(pSrc))
#define LIB_QUERY(lib_handle, proc) dlsym(lib_handle, proc)
#define Q_DEF_PROTOTYPE( Type, Name ) \
COPY_FP( p->Name, LIB_QUERY( g_library, STRINGIZE(FUNC(Name)) ) ); \
void dummy_##Name
Not sure, what "void dummy_##Name" does? Thanks.
It replace the ##Name with the value of Name parameter as string.
Q_DEF_PROTOTYPE(myType, objectName) => void dummy_objectName
Related
This question already has answers here:
What does ## (double hash) do in a preprocessor directive?
(2 answers)
Closed last month.
While reading this code in .h file about tlm,something that confuses me comes up:
//
// Generators for Setters and Getters.
//
#define CHIATTR_PROP_GETSET_GEN(name, type) \
type Get ## name (void) const { return name ; } \
void Set ## name (type new_v) { name = new_v; }
#define CHIATTR_PROP_GETSET_GEN_FUNC_NAME(func_name, prop_name, type) \
type Get ## func_name (void) const { return prop_name ; } \
void Set ## func_name (type new_v) { prop_name = new_v; }
and it is used like this:
CHIATTR_PROP_GETSET_GEN(ReturnNID_StashNID, uint16_t)
CHIATTR_PROP_GETSET_GEN_FUNC_NAME(ReturnNID,
ReturnNID_StashNID,
uint16_t)
what happens in this sentence?
type Get ## name (void) const { return name ; } \
Eagerly awaiting the answer!
The ## operator takes two separate tokens and pastes them together to form a single token.
From your examples :
CHIATTR_PROP_GETSET_GEN(ReturnNID_StashNID, uint16_t)
Would be replaced at the preprocessor step by the following code :
uint16_t GetReturnNID_StashNID (void) const { return ReturnNID_StashNID; }
void SetReturnNID_StashNID (uint16_t new_v) { ReturnNID_StashNID = new_v; }
How do I get the memory address of a class member function, I'm using a library statically that was previously setup dynamically, as the platform I ported the game to does not support dynamic libraries. It works well except for one issue.
When restoring a saved game NPCs become static as they don't continue to run the functions that were active when the game was saved. It did this by looking up the function address to get the name in the global offset table and symbol table when saving, when restoring it got the address using the name from the GOT and ST.
As this will not work with static linking I'm trying to figure out how to get the address of the exported functions to store it in a std::map with the address and a unique name when the application first starts.
The following doesn't seems to work for me for some reason. Any help would be much appreciated :).
Storing the address for the save game file in the base class using the DEFINE_FIELD macro:
// Global Savedata for Delay
TYPEDESCRIPTION CBaseEntity::m_SaveData[] =
{
DEFINE_FIELD( CBaseEntity, m_pfnThink, FIELD_FUNCTION )
};
Derived class export from when it was using dynamic linking:
extern "C" _declspec( dllexport ) void CMultiManager( entvars_t *pev );
Derived class where ManagerThink() was exported previously when it used dynamic linking:
class CMultiManager : public CBaseEntity
{
public:
CMultiManager();
void /*EXPORT*/ ManagerThink ( void );
}
My new class constructor in the derived class to try and get the address of the member function (so I can store it in std:map with a name). Is it possible to this in the global scope rather than a constructor?
CMultiManager::CMultiManager()
{
//Try the ManagerThink function directly
void (CBaseEntity ::*ptrTemp)(void);
ptrTemp = static_cast <void (CBaseEntity::*)(void)> (ManagerThink);
void* iMemoryAddressFunc = &ptrTemp;
ALERT( at_error, "__TEST__ FUCNTION __ EXPORT ADDRESS: CMultiManager::ManagerThink (%08lx)\n", (unsigned long)iMemoryAddressFunc );
//-------------------------------------------------------------------------------
//Try the inherited m_pfnThink variable ManagerThink() is stored in as well.
void* iMemoryAddressVar = &m_pfnThink;
ALERT( at_error, "__TEST__ M_PFNTHINK __ EXPORT ADDRESS:
CMultiManager::ManagerThink (%08lx)\n", (unsigned long)iMemoryAddressVar );
}
Function check method called before restoring the game, it's using the function address stored in the save game data in the base class (function above).
void FunctionCheck( void *pFunction, char *name )
{
if (pFunction && !NAME_FOR_FUNCTION((unsigned long)(pFunction)) )
ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (unsigned long)pFunction );
}
Debug log when running the game:
Obviously it's not going to find the export as I haven't setup anything yet as I need the address to store first, but why do the addresses not all match up? ManagerThink() has been assigned to m_pfnThink as well, so why are the first two in the log not at the same address at least?
From CMultiManager():
__TEST__ FUCNTION __ EXPORT ADDRESS: CMultiManager::ManagerThink (d008759c)
__TEST__ M_PFNTHINK __ EXPORT ADDRESS: CMultiManager::ManagerThink (01eb0e08)
From FunctionCheck();
No EXPORT: multi_manager:ManagerThink (00226c0a)
The ManagerThink() Function:
// Designers were using this to fire targets that may or may not exist --
// so I changed it to use the standard target fire code, made it a little simpler.
void CMultiManager :: ManagerThink ( void )
{
float time;
time = gpGlobals->time - m_startTime;
while ( m_index < m_cTargets && m_flTargetDelay[ m_index ] <= time )
{
FireTargets( STRING( m_iTargetName[ m_index ] ), m_hActivator, this, USE_TOGGLE, 0 );
m_index++;
}
if ( m_index >= m_cTargets )// have we fired all targets?
{
SetThink( NULL );
if ( IsClone() )
{
UTIL_Remove( this );
return;
}
SetUse ( ManagerUse );// allow manager re-use
}
else
pev->nextthink = m_startTime + m_flTargetDelay[ m_index ];
}
I'm also confused how it knew when setup dynamically which EXPORT ManagerThink ( void ); function to call for each instance of the object created, because it would have just stored the one EXPORT address in the GOT/symbol table right?
Any help/suggestions/advise would be great. Thank you :)
EDIT:
Thanks for the replies. I've managed to find a work around the issue.
I looked at a newer version of game where they updated the code to not use the GOT and ST as they needed the game on platforms that don't support dlls and were faced with the same issue. They solved it using the following macros to declare a structure and store defined pointers to member functions in the structure.
//-----------------------------------------------------------------------------
//
// Macros used to implement datadescs
//
#define DECLARE_SIMPLE_DATADESC() \
static datamap_t m_DataMap; \
static datamap_t *GetBaseMap(); \
template <typename T> friend void DataMapAccess(T *, datamap_t **p); \
template <typename T> friend datamap_t *DataMapInit(T *);
#define BEGIN_SIMPLE_DATADESC( className ) \
datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \
datamap_t *className::GetBaseMap() { return NULL; } \
BEGIN_DATADESC_GUTS( className )
#define BEGIN_SIMPLE_DATADESC_( className, BaseClass ) \
datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \
datamap_t *className::GetBaseMap() { datamap_t *pResult; DataMapAccess((BaseClass *)NULL, &pResult); return pResult; } \
BEGIN_DATADESC_GUTS( className )
#define DECLARE_DATADESC() \
DECLARE_SIMPLE_DATADESC() \
virtual datamap_t *GetDataDescMap( void );
#define BEGIN_DATADESC_NO_BASE( className ) \
datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \
datamap_t *className::GetDataDescMap( void ) { return &m_DataMap; } \
datamap_t *className::GetBaseMap() { return NULL; } \
BEGIN_DATADESC_GUTS( className )
#define BEGIN_DATADESC( className ) \
datamap_t className::m_DataMap = { 0, 0, #className, NULL }; \
datamap_t *className::GetDataDescMap( void ) { return &m_DataMap; } \
datamap_t *className::GetBaseMap() { datamap_t *pResult; DataMapAccess((CBaseEntity *)NULL, &pResult); return pResult; } \
BEGIN_DATADESC_GUTS( className )
#define BEGIN_DATADESC_GUTS( className ) \
template <typename T> datamap_t *DataMapInit(T *); \
template <> datamap_t *DataMapInit<className>( className * ); \
namespace className##_DataDescInit \
{ \
datamap_t *g_DataMapHolder = DataMapInit( (className *)NULL ); /* This can/will be used for some clean up duties later */ \
} \
\
template <> datamap_t *DataMapInit<className>( className * ) \
{ \
typedef className classNameTypedef; \
static CDatadescGeneratedNameHolder nameHolder(#className); \
className::m_DataMap.baseMap = className::GetBaseMap(); \
static typedescription_t dataDesc[] = \
{ \
{ FIELD_VOID, 0, 0, 0, 0 }, /* so you can define "empty" tables */
#define END_DATADESC() \
}; \
\
if ( sizeof( dataDesc ) > sizeof( dataDesc[0] ) ) \
{ \
classNameTypedef::m_DataMap.dataNumFields = SIZE_OF_ARRAY( dataDesc ) - 1; \
classNameTypedef::m_DataMap.dataDesc = &dataDesc[1]; \
} \
else \
{ \
classNameTypedef::m_DataMap.dataNumFields = 1; \
classNameTypedef::m_DataMap.dataDesc = dataDesc; \
} \
return &classNameTypedef::m_DataMap; \
}
// replaces EXPORT table for portability and non-DLL based systems (xbox)
#define DEFINE_FUNCTION_RAW( function, func_type ) { FIELD_VOID, nameHolder.GenerateName(#function), /*{ NULL, NULL },*/ 1, FTYPEDESC_FUNCTIONTABLE, /*NULL, NULL,*/ (inputfunc_t)((func_type)(&classNameTypedef::function))},
//------------------------------------------------------------------------------
// define the macro
#define FATAL(S,...) qDebug("%s,%s,%d,%s:"##S,"[scribble]",__FILE__,__LINE__,__FUNCTION__,##__VA_ARGS__)
// call the macro
FATAL("not supported commandid:%d",cmdid);
While this code works under Windows (Qt with msvc2010), when I try to compile it under macOS (Qt with clang), I get the error:::
pasting formed "%s,%s,%d,%s:""not supported commandid:%d", an invalid
preprocessing token.
How can I make it work under macOS, or is there another way to do the same function?
The token ## only has special meaning of indicating an optional argument when it is placed between a comma and a variable argument: , ##__VA_ARGS__
This is an extension to the C language.
In your example this is done correctly for the second argument, but not for the first.
If you don't need the first argument to be optional simply remove the token ##:
#define FATAL(S,...) printf("%s,%s,%d,%s:"S, \
"[scribble]",__FILE__,__LINE__,__FUNCTION__,##__VA_ARGS__)
But the first argument can be optional too, using another macro to expand the string literal and the first argument, while making the first argument optional:
#include <stdlib.h>
#include <stdio.h>
#define MERGE_EXPAND( a , ... ) a __VA_ARGS__
#define MERGE( a , ... ) MERGE_EXPAND( a , ##__VA_ARGS__ )
#define FATAL(S,...) printf( MERGE( "%s,%s,%d,%s:",S), \
"[scribble]",__FILE__,__LINE__,__FUNCTION__,##__VA_ARGS__)
int main( void )
{
int cmdid = 12345;
FATAL();
puts( "" ) ;
FATAL( "first argument" );
puts( "" ) ;
FATAL( "first and second arguments: %d" , cmdid );
return EXIT_SUCCESS ;
}
How to pass string or wstring to macro and print string in macro
i am tried something below
#define JUMP_ON_FAILURE_MSG( ErrorCode , Text ) GET_ERROR( ErrorCode, #Text )
#define GET_ERROR( ErrorCode, Text) \
{ \
if (ErrorCode < 0) \
{ \
wprintf(L"Error :%s :[%d]", #Text , error_code); \
} \
}
Above macro does not print proper output i gets
Error :??????????? :[-5200]
text not gets printed
i am calling above code as
JUMP_ON_FAILURE_MSG(-5200,L"Print error msg");
or
JUMP_ON_FAILURE_MSG(-5200,"Print error msg");
Please help
As others already pointed out in the comments you have to write
#define JUMP_ON_FAILURE_MSG( ErrorCode , Text ) GET_ERROR( ErrorCode, Text )
for instance. Without the #.
For further reference look here.
I want to create a macro that will accept arbitrary code block as its parameter like
FOR_VECTOR( type, vect, code_block ) \
for( vector<type>::iterator i=vect.begin(); i!=vect.end(); ++i ) { \
code_block; \
}
The problem is the code block in parameter, which may contain arbitrary number of , and ) characters.
Is there any good solution?
There are a number of possible solutions.
If you need only one expression (not a full-fashioned code block) - you can just enclose it in ( and )
FOR_VECTOR( int, v, (func(i,1)) )
will work - (func(i,1)) is treated like single macro argument
Another partial solution is variadic macros, if your preprocessor supports them.
You can define macros
#define COMMA ,
#define LPAR (
#define RPAR )
and use them to form your code block insted of real ( , and )
FOR_VECTOR( int, v, func LPAR i COMMA 1 RPAR )
It is not very readable though.
Or you can do a trick with commenting out quotes of a string literal after macro substitution:
FOR_VECTOR( type, vect, code_block ) \
for( vector<type>::iterator i=vect.begin(); i!=vect.end(); ++i ) { \
/code_block/; \
}
FOR_VECTOR( int, v, *"*/ func(i,1); proc(i,2); /*"* )
As #mas.morozov mentioned, you can use variadic macros:
#include <iostream>
#include <vector>
#define FOR_VECTOR( type, vect, ... ) \
for( std::vector<type>::iterator i=vect.begin(); i!=vect.end(); ++i ) { \
__VA_ARGS__ \
}
int main()
{
std::vector<int> v = {1, 2, 3, 4, 5, 6};
FOR_VECTOR(int, v, {
std::cout << *i << std::endl;
})
}
You can play with it online here: https://godbolt.org/z/oLWV-z
I found that solution here: https://mort.coffee/home/obscure-c-features/
You can also make a more generic FOR_CONTAINER macro:
#include <iostream>
#include <vector>
#define FOR_CONTAINER( container, ... ) \
for( decltype(container)::iterator i=container.begin(); i!=container.end(); ++i ) { \
__VA_ARGS__ \
}
int main()
{
std::vector<int> v = {1, 2, 3, 4, 5, 6};
FOR_CONTAINER(v, {
std::cout << *i << std::endl;
})
}
Try it here: https://godbolt.org/z/9Gzqja