Sign in to follow this  
adder_noir

Strange typedef declaration!

Recommended Posts

Hi guys, I've moved onto my book concerning game engines. I'd got as far as I could with my last book but have caved in and bought an easier C++ book to learn with. I believe it is called Effective C++, and has good reviews so might be a bit more helpful.

For now though I've decided to press on with the reason I decided to get better at C++ in the first place - my game engine book.

Check out the following code:

extern "C"
{
HRESULT CreateRenderDevice(HINSTANCE hDLL, ZFXRenderDevice** pInterface);

typedef HRESULT (*CREATERENDERDEVICE) (HINSTANCE hDLL, ZFXRenderDevice** pInterface);

HRESULT ReleaseRenderDevice(ZFXRenderDevice** pInterface);

typedef HRESULT (*RELEASERENDERDEVICE) (ZFXRenderDevice** pInterface);
}
Hmm... first things first. This takes place within I believe a static library that is used to initialise a DLL. Basically an object that implements an interface is created inside a DLL and it uses an interface defined within this static library. I'm sort of au fait with this bit but I'm not au fait with the syntax or why the author has chosen some of it. Here we go!

1)The extern keyword if I remember correctly has some effect on the compiler. I think it is necessary to have these things declared here so the file can be compiled but they cannot fully 'exist' here or there will be (I think) a linker problem where it finds two things where it should only find one and cannot resolve the discprency. I'd appreciate it if anyone can tell me if I'm correct here. Thanks.

2)WHat does the "C" part do? The author states that this "exports the functions in plain C-style without C++ name mangling" - "The overhead of object orientation forces C++ to twist around the function names and parameter lists a bit, but we don't want to worry about that and so we enforce plain C usage of those functions here". WHAT? So is he suggesting that there is some inherent flaw within C++ and C++ compilers that makes the basic functional modus operandi of the language useless without clever tricks and hacks? I don't think so somehow. SO what is he trying to achieve here? And what does any of that mean?

3)
typedef HRESULT (*CREATERENDERDEVICE) (HINSTANCE hDLL, ZFXRenderDevice** pInterface);
I don't understand this line? What is he typedef'ing here? I don't understand what the subject of the typedef is. Is it the function pointer or the argument list or what? Is somehow just doesn't look like a typical typedef statement to me.

That's it for now. ANy help anyone can offer would be appreicated cheers! :oD

Share this post


Link to post
Share on other sites
1 and 2) DLLs contain functions with a unique name. This is fine for languages like C, because no two functions can have the same name. However, C++ allows for function overloading, meaning that you can have:
void doSomething( int aNumber );
void doSomething( const char *aString );
at the same time. To uniquely identify those functions, the C++ compilers 'mangle' the function names to something that includes the parameters, and call them something like _doSomethingI and _doSomethingC.<br/>
When you declare these functions in a CPP-file, the linker will look for these mangled names in the library you load. Using extern "C" however, will tell the compiler/linker: I'm using a library that was written in C and does not use mangled names, please look for the functions with the names as I wrote them.

3) This typedef is a typedef of a function pointer (more specifically, the ones of the function declared above). The new name for the type is inside the first parentheses. So, with these declarations we can store a pointer to the function in some legible manner, like so:
CREATERENDERDEVICE createDevFnPtr = GetFunctionPointer(myDLL, "createRenderDevice");
.

Share this post


Link to post
Share on other sites
Quote:
Original post by adder_noir
2)WHat does the "C" part do? The author states that this "exports the functions in plain C-style without C++ name mangling" - "The overhead of object orientation forces C++ to twist around the function names and parameter lists a bit, but we don't want to worry about that and so we enforce plain C usage of those functions here". WHAT? So is he suggesting that there is some inherent flaw within C++ and C++ compilers that makes the basic functional modus operandi of the language useless without clever tricks and hacks?
Yes and no, there is an inherent flaw but it really only comes up when trying to have your code interact with dlls and libraries that were compiled differently (where different could mean different compiler options, different compilers, or even just different version of the same compiler) from your code.

The flaw being C++ doesn't have a standard way of mangling C++ identifiers to C-like equivalents. There are reasons why it probably will never become standardized. Hope this helps.

Share this post


Link to post
Share on other sites
C++ has no standard ABI, which is why most tools, languages, and systems (including the Win32 DLL system) perform interop through a common C-style ABI. C++ allows you to expose methods that conform to this interface by using the extern "C" { } construct at the expense of overloading those functions.

Share this post


Link to post
Share on other sites
Please excuse me, I've been knocked sideways by flu the last few days. I'll reply as soon as I can. I might even reply within the next hour or so but I'm not sure. Thanks to everyone who has replied so far ;o)

Share this post


Link to post
Share on other sites
Ok that's great I've got the "C" part of it now, makes much sense cheers.

As for the 'extern' part how far wide of the mark was i here:
Quote:
1)The extern keyword if I remember correctly has some effect on the compiler. I think it is necessary to have these things declared here so the file can be compiled but they cannot fully 'exist' here or there will be (I think) a linker problem where it finds two things where it should only find one and cannot resolve the discrepency. I'd appreciate it if anyone can tell me if I'm correct here. Thanks.


And one last thing, I still don't get why our man has had to typedef the function pointer. WHy can't he just declare a normal function pointer? In fact for that matter the typedef to me looks just like a regular function pointer declaration save for the typedef part.

typedef HRESULT (*CREATERENDERDEVICE) (HINSTANCE hDLL, ZFXRenderDevice** pInterface);


Looks like a regular function pointer definition to me. SHows the return type - a bracketed (no idea why) nametag with a * to show what it is, and the argument list. To me this is just a function pointer to a function which takes arguments (HINSTANCE hDLL, ZFXRenderDevice** pInterface); and returns a variable of type HRESULT. The function pointers name is CREATERENDERDEVICE.

That's where I am right now. I'm also still feeling rather ill with flu, missed a shift in work on Saturday night because of it which probably means I can't work there again :o( Anyway no worries looking forward to any help anyone can give me with this,

a big thumbs up to the three who've replied so far ;o)

Share this post


Link to post
Share on other sites
Quote:
Original post by CRYP7IK
I believe the typedef is done so it is easy to grab the function pointer later. For example:

*** Source Snippet Removed ***

Although I am not sure why he declares it beforehand...


That's what I thought, thanks for the reply. Thing is though I still don't understand why the typedef? I can't understand how it is any different from an ordinary function pointer declaration and furthermore why he can't just use an ordinary function pointer declaration in the first place.

I mean once you've defined a function pointer of type:
HRESULT (*CREATERENDERDEVICE) (HINSTANCE hDLL, ZFXRenderDevice** pInterface);
You now have a function pointer which can be referred to only by use of the name tag CREATERENDERDEVICE. It's not like every time you use it you need to state its return type and argument list, that's already done once only in the declaration.

I really don't see how a typedef is making anything more clearer later on. For example this I can understand that:
typedef unsigned int myInt;
myInt myIntInstance = 5;
saves us the pain of writing unsigned int all the time. I know pretty roughly how typedef works.

Just can't see how it's useful here though. WHy isn't it as simple as:
HRESULT (*CREATERENDERDEVICE) (HINSTANCE hDLL, ZFXRenderDevice** pInterface);

CREATERENDERDEVICE = getFunctionPointer();
where getFunctionPointer returns a function pointer of type CREATERENDERDEVICE?

***Update***

Actually I think I might be about to see the light on this one. I think I might be getting confused here between a variable's unique name/identifier and a variable 'type'. Feel free to reply for now while I go hammer away in the IDE and see if I can sort this out. Sorry if this seems a bit long winded but I really don't like progressing unless I properly understand stuff - that's how accidents happen ;o)

Share this post


Link to post
Share on other sites
Quote:

WHy isn't it as simple as:
HRESULT (*CREATERENDERDEVICE) (HINSTANCE hDLL, ZFXRenderDevice** pInterface);



CREATERENDERDEVICE = getFunctionPointer();
where getFunctionPointer returns a function pointer of type CREATERENDERDEVICE?

Library writers generally don't provide a getFunctionPointer() on a per-function basis. Instead there is one getFunctionPointer(), which returns an opaque pointer which will be casted to the correct type.

Thus:

CREATERENDERDEVICE createRenderDevice = (CREATERENDERDEVICE)getFunctionPointer();



The alternative is:

HRESULT (*createRenderDevice) (HINSTANCE hDLL, ZFXRenderDevice** pInterface) = (HRESULT (*) (HINSTANCE hDLL, ZFXRenderDevice** pInterface))getFunctionPointer();


Which is practically unreadable.

I always use a typedef for function pointers, even if I only use the typedef once, because it is so much easier to read.

Share this post


Link to post
Share on other sites
Ok finally I got it. I've understood much harder stuff than this before, seems I just wandered into the uncanny valley for a while. You know one of those times when your brain makes something so simple seem so complex, and you get stuck in your own maze for ages.

I see that the typedef - as already stated by another poster above - is creating a new data type if you like which is contained inside the first brackets, in this case CREATERENDERDEVICE.

SO now to refer to a function pointer of type:

HRESULT (*) (HINSTANCE hDLL, ZFXRenderDevice** pInterface);

all I have to do is write CREATERENDERDEVICE. Simple. I just hadn't ever seen a typedef used with a function pointer before and was getting confused as to whether CREATERENDERDEVICE was now a variable type or an actual individual variable. That alone was enough to cause so much confusion in me!

THis has been a most useful thread, which I can now finally draw to a close and progress onwards with. Thanks so much to all who participated ;oD

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
Quote:
Original post by Mike.Popoloski
C++ has no standard ABI

But neither does C, right?


On any given platform it pretty much does. It wouldn't be useful as the lingua franca for inter-language communication if it lacked one.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this