Understanding casting a struct as a void pointer - c++

I found this code in the rendering library for Quake 3. There is this function:
void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap );`
It is being called in a loop somehwere else like this:
R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse );
The weird part is that poly was declared as srfPoly_t *poly. What is going on
here? It is casting a srfPoly_t object to (void *) and then entering the
function as a surfaceType_t object.
Here are the declaration for the relevant structs:
typedef enum {
SF_BAD,
SF_SKIP, // ignore
SF_FACE,
SF_GRID,
SF_TRIANGLES,
SF_POLY,
SF_MD3,
SF_MD4,
SF_FLARE,
SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
SF_DISPLAY_LIST,
SF_NUM_SURFACE_TYPES,
SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
} surfaceType_t;
typedef struct srfPoly_s {
surfaceType_t surfaceType;
qhandle_t hShader;
int fogIndex;
int numVerts;
polyVert_t *verts;
} srfPoly_t;
This is working in C, but I am trying to implement something similar in C++,
but I get the following error:
Error 1 error C2664: 'int RefDef::AddDrawSurf(surfaceType_t *)' : cannot convert argument 1 from 'void *' to 'surfaceType_t *'
It would appear I cannot perform this type of cast in C++, or maybe there is
something else I am unable to understand. I am not very familiar with C++ and
would love to figure out how to set up something similar using it.
I am assuming this has something to do with type checking in C++, so it is not
allowed. How can I implement something similar in C++ in a safe way?

This works in C because structs are simply blocks of memory with each element in the struct laid out consecutively. This cast works because the first n bytes of a srfPoly_t struct consist of the surfaceType_t enum within that struct. The called function tries to interpret the passed-in srfPoly_t as a surfaceType_t, and succeeds because the first n bytes of the argument are, in fact, a surfaceType_t. Do not do this without a very good reason.
Casts from void*'s do not automatically occur in C++ as they do in C. You can use reinterpret_cast to explicitly cast between two different types of structs:
srfPoly_t* mySrfPoly_t;
surfaceType_t* mySurfaceType = reinterpret_cast<surfaceType_t*>(mySrfPoly_t);

Related

Trying to get past std::bind compile errors

I've used std::bind before and I think am close on this usage but not quite there and I don't have a clue how to resolve the compile error.
The ultimate goal is a medium-sized array of pointers to a small number of functions, with different parameters in each array element. At this point I just have one function and one table entry. If I can get that right I think I can solve the rest. I want to use std::function so that I can put the varied parameters into the array.
Here's declaration of the one function so far:
static Get *MakeGArrayStatic(void *Subscript, const void **array, unsigned int sizeOfArray);
Here's the declaration of the single pointer that will be typical of the array:
typedef std::tr1::function<Get *(void *, const void**, unsigned int)> GetMaker;
static GetMaker *gm1;
Here's the definition of the pointer:
Get::GetMaker *Get::gm1 = std::tr1::bind(&MakeGArrayStatic, &OutMsg::CurrentSeverity, FacSevTbls::SyslogSeveritiesForMessages, FacSevTbls::NumberOfTrueSeverities);
(Get is a class, CurrentSeverity is an enum, SyslogSeveritiesForMessages is a const char **, and NumberOfTrueSeverities is a size_t.)
The error I am getting (VS 2010) is
error C2440: 'initializing' : cannot convert from 'std::tr1::_Bind<_Result_type,_Ret,_BindN>' to 'Get::GetMaker *'
with
[
_Result_type=Get *,
_Ret=Get *,
_BindN=std::tr1::_Bind3,SyslogEnums::SeverityEnum *,const char **,size_t>
]
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Can anyone please point out where I am going wrong?
Thank you again to #PlinyTheElder but I think we have left the question "officially" unanswered. Closing the loop, here are the declarations with the first cut at an array of functions:
static Get *MakeGArrayStatic(void *Subscript, const char **array, size_t sizeOfArray);
static Get *MakeGStatic(void *field, size_t sizeOfField);
typedef std::tr1::function<Get *()> GetMaker;
static GetMaker gm[];
and here is the definition of the array so far:
std::tr1::function<Get *()> Get::gm[] = {
std::tr1::bind(&Get::MakeGArrayStatic, &OutMsg::CurrentSeverity, FacSevTbls::SyslogSeveritiesForMessages, FacSevTbls::NumberOfTrueSeverities),
std::tr1::bind(&MakeGStatic, Msg::MessageID, 8) } ;
And here is a trivial example of a call to a function:
Get *g = Get::gm[0]();
Came out better than I had hoped. I had pictured that all of the "little functions" were going to have to have the same signature (like overloads). Compiles cleanly on both target compilers. (Have not tested execution yet, but I am confident.) Thanks again!
Update: yes, it executes.

invalid conversion from 'long int' to 'void (*)()' [-fpermissive]

Hi I am writing little modified code for the bootloader for MCU's. The modification I am trying to do is power the boot loader even for an watchdog timer reset.
I am using this function prototype to define the address of the boot loader and I get the error :
invalid conversion from 'long int' to 'void (*)()' [-fpermissive]
My code is
#if defined ( __AVR_ATmega1284P__ )
void (*boot_start)(void) = 0xF000;
#elif defined ( __AVR_ATmega2560__ )
void (*boot_start)(void) = 0x1F000;
#endif
Where the 0xF000 and 0x1F000 are memory spaces. I don't get this error if my code is `
void (*boot_start)(void) = 0x0000;
Why ??
Compiler recognize 0xF000 as int and discard assigning this value to pointer. You should cast it explicitly:
void (*boot_start)(void) = (void (*)())0xF000;
0x0000 is just another name for NULL and will compile ok as a pointer value, but the other values need to be explicitly cast to the correct type.
The answer that I got from AVRFreak forum,
USE TYPEDEF,
typedef void (*fptr_t)(void);
fptr_t boot_start = (fptr_t)0xF000;
...
boot_start();
The reason you get the warning otherwise is that 0xF000 is a long int for an AVR. The thing on the left of '=' was a pointer to a function. So you are trying to assign an integer to a pointer. C thinks this is probably a mistake (often it is!) so it warns you. The way you quell that warning is to say "no this 0xF000 number really is a pointer value". The way you do that is with a typecast. Now you could do this with (wait for it):
void (*boot_start)(void) = (void(*)(void))0xF000;
But as you can see in that there is almost exactly the same (quite complex) structure on both side of the equals. So it makes sense to put all that detail into one single typedef and use it in multiple places.
If the function type were more complex this might even be something like:
int (*boot_start)(char, long, int *) = (int (*)(char, long, int *))0xF000;
and this starts to look very silly indeed - not only is it very likely you make a typing error it's just trying to remember the syntax here is a real pain! So you use typedef to define the function interface just once:
typedef int (*myfn_t)(char, long, int *);
myfn_t boot_start = (myfn_t))0xF000;
and that gets to be easier to type and easier to manage. If you later add a fourth char ** parameter to the function you now do it in just one place - the typedef.
Thanks to C Lawson and Yuriy.

Detours - Hooking a Classes Member Function - Syntax for setting function offset of target?

For non class functions - I can simply declare the offset of the function to be detoured like:
typedef int (_cdecl* SomeFunc)(char* pBuffer, int size);
SomeFunc Real_SomeFunc = (SomeFunc)(0xCAFEBABE);
...
DetourAttach(&(PVOID&)Real_SomeFunc, (PVOID)Hook_SomeFunc);
Now, this gets hard with detouring member functions of classes - detours has a sample for this:
https://github.com/microsoft/Detours/blob/master/samples/member/member.cpp
That sample already defines the targets member function - but I dont I only know the offset in the binary im injecting my DLL into - so how do I convert this
void (CDetour::* CDetour::Real_Target)(void) =
(void (CDetour::*)(void))&CMember::Target;
to something like this:
void (CDetour::* CDetour::Real_Target)(void) =
(void (CDetour::*)(void))0xCAFEBABE;
I'm getting a compile error here
Any hints?
void (CDetour::* CDetour::Real_Target)(void) = (void (CDetour::*)(void))0xCAFEBABE;
I'm getting a compile error here
Specifically, it's error C2440: 'type cast' : cannot convert from 'unsigned int' to 'void (__thiscall CDetour::* )(void). There are no conversions from integral values to pointer-to-member values. Conversion to member pointers is a non-trivial beast - they may or may not be simple memory addresses, depending on the type of member function and complexity of the class hierarchy. Multiple virtual inheritance adds extra fields to this pseudo data structure; aside from the code address, there's also re-basing information. The format of this data is compiler-specific.
For my purposes, I use this MSVC-specific macro:
/// Void pointer to Func pointer.
/// Assumes first four bytes should hold the address and rest be zero.
template<typename T> T VTOF(void* ptr)
{// fills in 4 bytes and zeroes the rest
T result = 0;
*(void**)&result = ptr;
return result;
}
Usage: ptr = VTOF<void (CDetour::*)(void)>((void*)0xCAFEBABE);
Now, this obviously won't work in real complex code, but I assume it'll be good enough to work in a call to the original in a hook. It's been a while since I've had to use this on member function pointers.

How to use a Judy array

I am interested in Judy Arrays and try to use it. But i had unable to do any useful thing using it. Every time it gives me casting errors.. Sample c++ code and the error given below.
#include "Judy.h"
#include <iostream>
using namespace std;
int main()
{
int Rc_int; // return code - integer
Word_t Rc_word; // return code - unsigned word
Word_t Index = 12, Index1 = 34, Index2 = 55, Nth;
Word_t PValue; // pointer to return value
//Pvoid_t PJLArray = NULL; // initialize JudyL array
Pvoid_t JudyArray = NULL;
char String[100];
PWord_t _PValue;
JSLI( JudyArray, _PValue, (uint8_t *) String);
return(0);
} // main()
This gives me the error
m.cpp: In function ‘int main()’:
m.cpp:19: error: invalid conversion from ‘long unsigned int**’ to ‘void**’
m.cpp:19: error: initializing argument 1 of ‘void** JudySLIns(void**, const uint8_t*, J_UDY_ERROR_STRUCT*)’
Please anyone help me to figure out what is the error what i'm doing..
Thanks
According to the documentation, you have the _PValue and JudyArray parameters reversed. Make your call look like this:
JSLI( _PValue, JudyArray, (uint8_t *) String);
Also, try not compiling it as C++ code. So far, your test uses no C++ features. I bet it will compile as C code. It looks like JudyArray relies on the fact that C will do certain kinds of implicit conversions between void * and other pointer types.
If this is the case, I'm not sure what to do about it. The error messages you're getting tell me that JSLI is a macro. In order to fix the error message you have in the comments on this answer, you'd have to reach inside the macro and add a typecast.
These kinds of implicit conversions are allowed in C because otherwise using malloc would always require ugly casts. C++ purposely disallows them because the semantics of new make the requirement that the result of malloc be cast to the correct type unimportant.
I don't think this library can be used effectively in C++ for this reason.
It seems that, you pass JudySLIns(void**, const uint8_t*, J_UDY_ERROR_STRUCT*) a wrong parameter, the first one, you'b better check it!
For integer keys there is a C++ wrapper at http://judyhash.sourceforge.net/

Prevent array decaying to ** from *[N]

I have declared my array like this:
FT_Interface<4096> *to_make_ft[3] = { /* initialization with existing objects */ };
my interface is declared like this:
template<cyg_ucount32 S, int N>
class FT_Thread {
FT_Thread(FT_Interface<S> *entry[N]){}
};
And i call it (as expected with):
FT_Thread<4096, 3> ft(to_make_ft);
Yet it complains that the pointer has decayed.
ecos/install/include/ft/thread.hxx:70: error: incompatible types in assignment of ‘FT_Interface<4096u>**’ to ‘FT_Interface<4096u>* [3]’
Is there any way to prevent this from happening?
You need
FT_Thread(FT_Interface<S>* (&entry)[N]){}
// note these ^^-----^
With that, you get a reference to the array.
Edit: Of course, if you want a pointer to the array, you can have just that:
FT_Thread(FT_Interface<S>* (*entry)[N]){}
Though you need to call it with FT_Thread<4096,3> ft(&to_make_ft).
I don't know if this is right, but try changing
FT_Thread(FT_Interface<S> *entry[N]){}
to
FT_Thread(FT_Interface<S> (*entry[N])){}
I have a feeling that the compiler thinks that the * refers to the FT_Interface rather than the entry.