Handmade Hero » Forums » Code » X_INPUT_GET_STATE confusion.
zipzoomzap
7 posts
#331 X_INPUT_GET_STATE confusion.
3 years ago

Hi guys.

I'm wondering if someone could be kind enough to explain what's going on for the X_INPUT_GET_STATE #define and typedef.

I understand the purpose of the code, I'm just not getting the why. I'm trying really grill all this code into my head.

1
2
3
4
5
6
7
8
#define X_INPUT_GET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_STATE *pState)
typedef X_INPUT_GET_STATE(x_input_get_state);
X_INPUT_GET_STATE(XInputGetStateStub)
{
	return(ERROR_DEVICE_NOT_CONNECTED);
}
global_variable x_input_get_state *XInputGetState_ = XInputGetStateStub;
#define XInputGetState XInputGetState_ 


The first line I understand, we're just 'mapping' X_INPUT_... to call the Windows function, but what are the name attributes doing here?

The second line I think is a function pointer? The function definition from line 3 is throwing me off completely.

I don't understand how XInputGetStateStub can be assigned to *XInputGetState_, infact I can't see how it can actually be anything at all?

I understand the final #define.

Sorry if I'm asking a lot but I'm banging my head against a wall here.

thanks.
UplinkCoder
Stefan Koch
22 posts
#333 X_INPUT_GET_STATE confusion.
3 years ago

XInputGetState_ is a function pointer.
that function pointer is assigned the address of the stub function.
zipzoomzap
7 posts
#335 X_INPUT_GET_STATE confusion.
3 years ago

UplinkCoder
XInputGetState_ is a function pointer.
that function pointer is assigned the address of the stub function.


hmm, I get that. I just don't understand how it's all working together.

I assume the second line is also a function pointer? The first #define and the name parameter means its expanded out to a function pointer to (or named) WINAPI x_input_get_state(DWORD......)

line 3 onwards is throwing me, I cannot figure out what the stub is supposed to be doing. How does x_input_get_state become a type? The more I try to think of this the more confusing it is.
Nimbal
Benjamin Kloster
49 posts
#338 X_INPUT_GET_STATE confusion.
3 years ago

The first line I understand, we're just 'mapping' X_INPUT_... to call the Windows function, [...]

No, it's a macro that just saves us some typing in the following lines.

The second line I think is a function pointer?
xinput_get_state is a typedef for the type of the function pointer. Imagine what the preprocessor makes out of this line. It takes the macro from the first line and basically replaces line 2 with this:

1
typedef DWORD WINAPI xinput_get_state(DWORD dwUserIndex, XINPUT_STATE *pState)

That's how you typedef a function pointer type (important distinction between function pointer and its type here). Sometimes, you also see this form:

1
typedef DWORD WINAPI (*xinput_get_state)(DWORD dwUserIndex, XINPUT_STATE *pState)


The difference is that with the former, you need to declare function pointer variables like this:

1
x_input_get_state* functionPointer;


With the latter, you can declare them like this (note the lacking asterisk):

1
x_input_get_state functionPointer;


The asterisk is basically "baked in".

Onto line 3, the stub. Note again the use of our X_INPUT_GET_STATE stub so we don't have to type that function signature again. Write out what the preprocessor makes out of this line and it will be clear, I hope.

The stub is there to have something to call when the DLL can not be loaded (or it doesn't contain an XInputGetState symbol). Instead of a stub, you could also wrap all calls to XInputGetState like this:

1
2
3
if (XInputGetState) {
    XInputGetState(...);
}


Using a stub makes the control flow in the main function a little clearer, though.

This line:

1
global_variable x_input_get_state *XInputGetState_ = XInputGetStateStub;

Defines a global variable of type x_input_get_state* (our typedef), called XInputGetState_ (underscore to not collide with the real XInputGetState from the XInput.h header) and initializes it to the stub.

And finally, to save us from having to type that underscore all the time:

#define XInputGetState XInputGetState_

We tell the preprocessor to replace all occurences of XInputGetState below this line by XInputGetState_ so that it calls our function pointer instead of the one declared in XInput.h.
zipzoomzap
7 posts
#339 X_INPUT_GET_STATE confusion.
3 years ago

okay, big thanks!

I think I've just about got it. If I'm following correctly, if I expand out the macros, lines two and three are going to become:

1
2
3
4
5
x_input_get_state(DWORD dwUserIndex, ....)
XInputGetStateStub
{
    return(ERROR)
}


The fourth line: x_input_get_state is coming from second line once expanded out?

the final #define makes sense, I get that.

it's just hard to follow, but I want to understand this instead of just accepting it for what it is.
UplinkCoder
Stefan Koch
22 posts
#340 X_INPUT_GET_STATE confusion.
3 years ago

That is the spirit!
venfayth
2 posts

None

#959 X_INPUT_GET_STATE confusion.
2 years, 11 months ago

Sorry to revive this, I am stuck here as well.

Thanks to steelgolem and christianrohr and garlandobloom in the twitch chat for answering some of my questions. I am rather new to C, I've mostly learned Python, although a long time ago I took some classes on Java and also Scheme/LISP

http://pastebin.com/y8PH5zhF

In our Win32LoadXInput function, we have this line:

1
XInputGetState = (x_input_get_state *)GetProcAddress(XInputLibrary, "XInputGetState")


XInputGetState is actually XInputGetState_ which is a pointer to a function of type x_input_get_state.

So, we are assigning the value of that pointer to be the same thing as: The address of the XInputGetState function in our XInputLibrary.

What I'm confused about here is how the typecasting works. Would this typecast completely fail if our x_input_get_state function was not defined with the same format and return type as the XInputGetState in the XInput DLL?

Or does C not even care and just try to fit the address in as best as it can?

--

I think, despite this question, after thinking about / asking questions about this XInput stuff for nearly an entire day, I have a pretty good grasp of what's going on now. Thanks again to everyone who has answered my questions and helped me!

None
IanM
Ian
6 posts
#960 X_INPUT_GET_STATE confusion.
2 years, 11 months ago

There's no simple way to identify the return type and parameter types of the XInputGetState function in the DLL - you have to know all of these to use the function correctly, in addition to the name in the DLL.

In addition the GetProcAddress simply returns a void* pointer to the function - to make that pointer usable we have to cast it to the correct type before assigning it to a variable of the same type.
Starmony
JesseF
2 posts
#13214 X_INPUT_GET_STATE confusion.
2 months, 1 week ago

Gonna bump this up one more time for a detail I'm confused about.

In the #define line, what is the variable "name" in X_INPUT_GET_STATE(name) doing?

VS seems to get "name" from an exception class in math.h but I tested it and it can be substituted for anything.

I think I understand what the typedef is doing but I don't get how the compiler knows to swap "name" for x_input_get_state.

Is it like an argument for a "function name"?

like how you don't have to declare a type if you did
#define min(X, Y) ((X) < (Y) ? (X) : (Y))

Trying to google it but it's difficult when you don't know the right vocabulary.
shogas
1 posts
#13215 X_INPUT_GET_STATE confusion.
2 months, 1 week ago

The name is just the parameter to the macro, and the invocation on line 2 in the original post gives "x_input_get_state" as that parameter. In this case, you can look at the preprocessor macro as doing simple string replacement. Line 2 in op is expanded (following are the same line):

1
2
3
typedef X_INPUT_GET_STATE(x_input_get_state);                      // Original line (parameter is x_input_get_state)
typedef DWORD WINAPI name(DWORD dwUserIndex, XINPUT_STATE *pState) // Macro contents inserted
typedef DWORD WINAPI x_input_get_state(DWORD dwUserIndex, XINPUT_STATE *pState) // name is replaced with the parameter (x_input_get_state)

This is the type definition for a function taking two parameters (DWORD dwUserIndex, XINPUT_STATE *pState), returning "DWORD WINAPI".

The following line then creates a separate function with the same function signature, which by expansion is

1
2
3
X_INPUT_GET_STATE(XInputGetStateStub)
DWORD WINAPI name(DWORD dwUserIndex, XINPUT_STATE *pState) // name == XInputGetStateStub
DWORD WINAPI XInputGetStateStub(DWORD dwUserIndex, XINPUT_STATE *pState) // name inserted


Since XinputGetStateStub has the same signature as the type x_input_get_state, a function pointer can be assigned in line 7 in the op
Starmony
JesseF
2 posts
#13216 X_INPUT_GET_STATE confusion.
2 months, 1 week ago

shogas
snip


Ahh they're parameters. Thanks for your thoroughness.
Looking through preprocessor syntax with that in mind makes a lot more sense.

Thinking about a pointer-to-a-function as a type has been difficult. If anyone looking at this thread is still confused, Casey did a 4 HOUR LONG stream on the subject (search for chat 013) that covers how function pointers are related to compilation, translation units, and the preprocessor.