Use of brackets with typedef in dll video examples... Help?


10 replies [Last post]
clickykeys
clickykeys's picture
Offline
Joined: 2012-07-18
Points: 0

I'm not really clear about whats happening in the MyCaller.c source code in the dll video series.

The lines 5 & 6, I find confusing:

<code>

typedef void (*HeyBuddyPrt) ();

HeyBuddyPrt HeyBuddy;

</code>

 

 

It is the syntax I am struggling with I guess, why the brackets?... are we declaring a HeyBuddyPtr function called HeyBuddy on line 6?

 

Thanks for any help, waiting on that eureka moment.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Alder
Alder's picture
Offline
Joined: 2012-07-19
Points: 0

This is confusing to me as well.  Actually, the whole thing about a pointer to a function is kind of weird.  But doesn't the "HeyBuddy" in that code refer to the HeyBuddy function in the DLL, not a local reference?  Or they just happen to have the same name?  

Kevin
Offline
When things break I did it. I am an admin!Enjoy my soothing baritone.Completionist. I am better than you.My name if Forest WiBit.Nothing on Earth could stop the coding...A Coding BeautyDriving Ms. ChickyYou maniac! You blew it up! The compiler that is.Halfsies!W007! I watched 10 vids!Boot up or shut up!I don't know when to shut up.I'm not a fanboy!
Joined: 2011-03-20
Points: 2570

We are creating a type definition. So the line that says

typedef void (*HeyBuddyPrt) ();

Is basically stating that we are creating a label that will represent a function pointer. Think of this line as saying:

I want to create a label that will act like a datatype. This label will be called HeyBuddyPtr. The HeyBuddyPtr datatype (or TypeDef) will be able to store a pointer to a function that takes no params and returns void.

Try not to over think this... All we are doing is creating a label that represents a pointer to a function that takes no params and returns void. This is really no different than using a typedef for structs like in our C class:

Here is a struct:

struct MyStruct
{
  int x;
};

To declare this in C code I need to do this:

struct MyStruct s;

I can use a typedef to create a label that will represent the struct, so I can rewrite my struct like this:

typedef struct
{
  int x;
} MyStruct;

This allows me to declare the struct like this:

MyStruct s;

You see, by using typedef the label MyStruct can represent a struct that contains an integer called 'x'. You can even use easier examples such as:

typdef int INTEGER;
// Now if I use INTEGER it will represent an int
INTEGER x = 99; // same as int x = 99;

typedef float FLOAT;
// Now if I use FLOAT it will represent a float
FLOAT f = 0.1f; // same as float f = 0.1f;

typedef char* STRING;
STRING s = "Hey Buddy!"; // same as char* s = "Hey Buddy";

I am not sure if that cleared things up, but I will continue anyways.

OK, so now that we have created our typedef (which simply represents a function pointer that takes no params and returns void) I can create a variable that can represend one:

HeyBuddyPrt HeyBuddy;

Later in this code example we are referencing a function that loads a function from a DLL (that takes no params and returns void) and the variable HeyBuddy can be called like a function:

HeyBuddy();

clickykeys
clickykeys's picture
Offline
Joined: 2012-07-18
Points: 0

Yes! Thanks very much! I get it now, I think...

C just has a special syntax for 'typedef'ing, or more correctly put, labeling a function pointer data type.

 

 

 

Alder
Alder's picture
Offline
Joined: 2012-07-19
Points: 0

Thanks, Kevin.  I think I'm good on typedef with structs and primitive datatypes, but the function pointer syntax is a little different, isn't it?  For the others, it was:

typdef int INTEGER;

typedef <stuff> <label>;

 

When creating typedef for a function pointer, it was:

typedef void (*HeyBuddyPtr) ();

Does that follow the same pattern?  

typedef <return type> <name> <params>;

Where, later in the program, you can use it as a datatype...:

HeyBuddyPtr HeyBuddy;

I think I get it.  Here's my question:  In the main function, we use it like this:

 

HINSTANCE HeyBuddyLib = LoadLibrary("HeyBuddy.dll");

HeyBuddy = (HeyBuddyPrt)GetProcAddress(HeyBuddyLib, "HeyBuddy");

 

How would you do this without using typedef?  

Kevin
Offline
When things break I did it. I am an admin!Enjoy my soothing baritone.Completionist. I am better than you.My name if Forest WiBit.Nothing on Earth could stop the coding...A Coding BeautyDriving Ms. ChickyYou maniac! You blew it up! The compiler that is.Halfsies!W007! I watched 10 vids!Boot up or shut up!I don't know when to shut up.I'm not a fanboy!
Joined: 2011-03-20
Points: 2570

OK, your question is totally logical and I understand the confusion. The syntax is different simply because function pointers do not follow typical naming standards (as primitives and pointers do).

A function needs to have a return type and params, which a typical composite/primitive datatype does not. That is why the syntax is not the same.

Here is an example of the sort dll code that does not use typedef. Take a look and let me know if this answeres your question:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>

void loadNumbersArray(int[], int, int);
void printArray(int[], int);

int main()
{
	srand(time(NULL));
	HINSTANCE IntegerSortLib = LoadLibrary("integersort.dll");
	if(!IntegerSortLib)
	{
		puts("Error loading DLL.");
		return 1;
	}
	
	void (*bubbleSort)(int[], int) = GetProcAddress(IntegerSortLib, "bubbleSortArray");
	const int arrayLength = 10, numberMax = 5000;
	int arrayToSort[arrayLength];
	loadNumbersArray(arrayToSort, arrayLength, numberMax);
	
	puts("Unsorted list:"); printArray(arrayToSort, arrayLength);
	bubbleSort(arrayToSort, arrayLength);
	puts("Sorted list:"); printArray(arrayToSort, arrayLength);
	FreeLibrary(IntegerSortLib);
	return 0;
}

void loadNumbersArray(int arr[], int size, int max)
{
	int i;
	for(i = 0; i < size; i++)
		arr[i] = rand() % max + 1;
}

void printArray(int arr[], int size)
{
	int i;
	for(i = 0; i < size; i++)
		printf("%d\n", arr[i]);
}

Alder
Alder's picture
Offline
Joined: 2012-07-19
Points: 0

Ahh.. okay, interesting.  So in the case of a function pointer, typedef isn't really creating some label to stuff, it's just defining it to be treated as a datatype?  So when we say "HeyBuddyPtr HeyBuddy;", are we essentially creating an instance of the HeyBuddyPtr called HeyBuddy?  I noticed you could also do it this way:

 

 

#include <stdio.h>

#include <windows.h>

 

void (*HeyBuddyPrt)();

 

int main()

{

//Points to a resource

HINSTANCE HeyBuddyLib = LoadLibrary("HeyBuddy.dll");

HeyBuddyPrt = GetProcAddress(HeyBuddyLib, "HeyBuddy");

HeyBuddyPrt();

FreeLibrary(HeyBuddyLib);

return 0;

}

 

 

 

It works, but gives me a warning on the "HeyBuddyPrt();" line.  In what way exactly is using typedef more efficient -- does it let you create multiple void, no-param functions if you have more than one?  

Kevin
Offline
When things break I did it. I am an admin!Enjoy my soothing baritone.Completionist. I am better than you.My name if Forest WiBit.Nothing on Earth could stop the coding...A Coding BeautyDriving Ms. ChickyYou maniac! You blew it up! The compiler that is.Halfsies!W007! I watched 10 vids!Boot up or shut up!I don't know when to shut up.I'm not a fanboy!
Joined: 2011-03-20
Points: 2570

The best way I can describe it is that typedef gives you a label that acts like a datatype. So, if we have this we can use it for other functions, such as type casting. If you use typedef and typecase the GetProcAddress result then you will not have that warning. The code functions perfectly find the way you have it above, however, it is not considered the proper way to do it. Typedef just gives us more flexability.

If you go back and watch the videos, Bryan and I sort of make fun of typedef in the Structs video, stating that "it's just lazy." Eventhough that is our view, using typedef in structs is all over the place in production code. 

The major benefit to using typedef in this example is for ease of reading the code. As far as notable performance implications, I am not aware of any. C executes so fast anyway, there is probably little-to-no performance increase using typedef.

My opinion, using typedef in this situation is a good idea. I personally think it makes the code read better.

LoveCats
LoveCats's picture
Offline
W007! I watched 10 vids!
Joined: 2011-06-25
Points: 10

I would like to ask how

MyStruct s;

is more readbale than

struct MyStruct s;

 

As you can see, in the first one, if the name is something like Random S, the other user will have no clue what exactly Random is? I mean, it could be an alias for Int. While in the second one, despite of the name, its clear that its a structure defined somewhere.

 

So how typedef is making the code more readable?

Alder
Alder's picture
Offline
Joined: 2012-07-19
Points: 0

LoveCats wrote:

I would like to ask how

MyStruct s;

is more readbale than

struct MyStruct s;

 

As you can see, in the first one, if the name is something like Random S, the other user will have no clue what exactly Random is? I mean, it could be an alias for Int. While in the second one, despite of the name, its clear that its a structure defined somewhere.

 

So how typedef is making the code more readable?

 

I think he was saying that typedef is more readable in the case of function pointers, not necessarily structs.  

But anyway, thanks for the help Kevin :)

Kevin
Offline
When things break I did it. I am an admin!Enjoy my soothing baritone.Completionist. I am better than you.My name if Forest WiBit.Nothing on Earth could stop the coding...A Coding BeautyDriving Ms. ChickyYou maniac! You blew it up! The compiler that is.Halfsies!W007! I watched 10 vids!Boot up or shut up!I don't know when to shut up.I'm not a fanboy!
Joined: 2011-03-20
Points: 2570

You bring up a great question and one that you will ask constantly as you progress as a programmer. The simple question is “why?” I ask this question constantly. Sometimes the answer is just as simple as what the Terminator told John Connor in Terminator 2 (“Because you told me to”): http://wavs.unclebubby.com/wav/MOVIES/T2/whydothat_t2.wav

I was mainly referring to the readability typedef provides when declaring a function pointer. The struct syntax is subjective. Some people find one way easier to understand, and some the other

I actually agree with you when you bring up a struct. I think it is easier to know you are working with a struct if you declare it as a struct.

struct MyStruct s;
// VS
MyStruct s;

Many people disagree with this, and that’s fine! That’s life, not everyone agrees with everyone.

I do believe that using typedef in the context of a function pointer makes the code a lot easier to follow. This may be a bad example because it is so short, but constantly declaring a function pointer can be quite confusing if you are just simply trying to read the code to figure out “what it does.” One thing developers forget is that they need to write code so that their "future self" can read it. Bryan and I always say that you are not the same person now that you were 6 months ago, and something that made sense then is totally off the wall now! We have read code and asked ourselves "what kind of an asshole would write code like this?" and then later find out that it was something we wrote 2 years ago, ha ha ha. Using typedef for function pointers, in my opinion, will help you more quickly read the code months later when you revisit it, OR it will help someone that inherits the code after you're no longer on the project.

void (*function1)(int[], int, char, char*, int*, MyStruct*) = GetProcAddress(hInstance, "Function1");
void (*function2)(int[], int, char, char*, int*, MyStruct*) = GetProcAddress(hInstance, "Function2");
void (*function3)(int[], int, char, char*, int*, MyStruct*) = GetProcAddress(hInstance, "Function3");
void (*function4)(int[], int, char, char*, int*, MyStruct*) = GetProcAddress(hInstance, "Function4");
void (*function5)(int[], int, char, char*, int*, MyStruct*) = GetProcAddress(hInstance, "Function5");
// VS
typedef void (*DllFunction)(int[], int, char, char*, int*, MyStruct*);
DllFunction function1 = GetProcAddress(hInstance, "Function1");
DllFunction function2 = GetProcAddress(hInstance, "Function2");
DllFunction function3 = GetProcAddress(hInstance, "Function3");
DllFunction function4 = GetProcAddress(hInstance, "Function4");
DllFunction function5 = GetProcAddress(hInstance, "Function5");

You are free to disagree, but…. YOU’RE WRONG IF YOU DISAGREE WITH ME!!! Ha ha ha, just kidding