look through old code,
you see a lot of
redundant function pointer casts.
(If you're writing new code,
you should get rid of as many function pointer casts as possible,
a function pointer cast is a bug waiting to happen.)
Why does old code have so many redundant function pointer casts?
Because back in the old days, they weren't redundant.
In the days of 16-bit Windows,
function prologues were required to take very specific forms
in order to make
stack walking work,
and stack walking was necessary in order to simulate an MMU
on a CPU that didn't have one.
Another rule for prologues has to do with state management.
The full prologue for a far function looks like this:
mov ax, ds
mov bp, sp
mov ds, ax
Before we can dig into those instructions, we need to know a bit about
how code segments worked in real-mode 16-bit Windows.
In real-mode 16-bit Windows, there was a single address space for all applications
because the CPU had no concept of per-process address spaces.
The kernel simulated separate address spaces by managing instances.
The instance (represented by an instance handle)
specified the location of the data segment the code should operate on.
If you have two copies of a program running,
the code is shared, but each program has its own data.
The instance handle tells you where that data is.
And the instance handle is kept in the
Therefore, it is essential that every function have its
register set to the instance handle that describes where the code
should find its data.
You can think of it as a "global
this pointer for the process."
Okay, so let's look at the function prologue again.
First, it copies
ax via a two-byte
mov ax, ds instruction.
Then there is a
This pads the prologue size to three bytes.
The next four instructions build the stack frame:
marks the stack frame as a far frame.
push bp and
mov bp, sp
push ds saves the original
which also provides breathing room for
return address patching.
And then we move
ax back into
The instance handle just took a little tour of the
register and then returned back home.
What was the point of that?
Recall that in 16-bit Windows,
every far function called from another segment was listed
in the module's Entry Table.
When a far function is placed in the exported function table,
the loader patches the first three bytes of the function
Non-exported functions remain unchanged.
This means that non-exported functions do the redundant
It's a little extra work, but it's ultimately harmless.
The effect of patching out the initial
mov ax, ds
is that the function ends up doing this:
- Build a far stack frame,
which includes saving the original
dsto whatever was passed in the
The second step means that the code, when it executes,
operates on the data associated with the handle passed in the
Okay, great, but this means that you can't call an exported function
because it will set the
ds register to whatever
value is passed in the
ax register is not part of the calling convention,
its value is garbage.
But that's okay.
We made things worse so we can make them better.
creates a stub function that loads the
with the instance handle you provide,
and then jumps to the function you provide.
That's all it did.
(When you're done, you call
to free the memory back to the system.)
This stub function was known as
a procedure instance thunk,
or a proc instance for short.
Hence the name
Okay, finally the punch line.
MakeProcInstance function didn't care
what kind of function pointer you passed it.
Whatever you passed in, it returned the same kind of pointer back out,
because all the stub did was twiddle the
and then jump to the real function.
The parameters on the stack didn't change,
the cleanup convention didn't change,
nothing else changed.
MakeProcInstance function was
declared as returning a
which is a typedef for a far function that takes no parameters
and returns nothing.
The parameters and return value are irrelevant;
it just had to be something.
But what this means is that when you take your function,
like a window enumeration callback,
and create a procedure instance for it,
the thing you get back has been type-erased to a generic
To make it useful again, you need to cast it back to what it
For example, if what you passed was a
then you need to cast the procedure instance back to a
If you passed a
TIMERPROC, then you need to cast
the procedure instance back to a
You could anachronistically express this as
auto MakeProcInstanceT(R (FAR *func)(Args...), HINSTANCE inst)
return (decltype(func))MakeProcInstance((FARPROC)func, inst);
Of course, you didn't have this fancy template deduction
in 1983-era C,
so you had to cast the return value manually.
And that brings us to today.
MakeProcInstance has been obsolete
some people imprinted on the
"gotta cast your function pointers to get them to compile"
either because they wrote code when the cast was required
and fell into the habit, or
or (more likely) they learned from code that was written
by someone who inherited this habit from somebody else.
And yes, this inherited folk wisdom
can even be found in MSDN.
The redundant function pointer cast is now a type of folklore,
passed down from developer to developer,
even though it's no longer needed
and in fact
will mask problems
caused by mismatched prototypes.
This post first appeared on MSDN Blogs | Get The Latest Information, Insights, Announcements, And News From Microsoft Experts And Developers In The MSDN Blogs., please read the originial post: here