Hello, this is Dr. Miller and this
is Episode fourteen point eight of
Assembly.
Today, we're going to talk about
function pointers.
Function pointers.
So a function pointer points to a
function or a subroutine, as it
sometimes is called, and
what this allows us to do is it
allows us to change the
functionality of a program at
runtime and so we can call different
functions based on
that. And there are several
different uses.
So one is closure's
or curried
functions. And so that's one
example.
Interrupt handlers or another.
And then if we have virtual
functions inside of C++
or doing object oriented programing
design.
So, Nancy, the syntax
includes the arguments and it
includes the return type
and the argument types, so each one
of those is listed so
we can see that in a normal function
declaration, we have our return
type. We then have our
arguments. So we have an integer
called X, A double called B
and A float called C.
And so when we create a function
pointer, we say the return type.
So this returns a character and
then we just give the types of the
arguments in here.
So we have int double and float
and we have to put those inside
parentheses so it knows those
are part of that.
And then here we give it a name
and we say that this is a pointer
to a function that takes an int a
double and a float and returns a
character.
And so that fun pointer is the name
of the pointer that we're creating
for this function inside of C.
So once you've created a function
pointer, you can use it just like
any other function.
So I can have
my fun is the actual
function. It returns a character and
I can just use function pointer in
the same type of syntax.
We can also assign it a value.
So if we have a function pointer, we
can say our pointer is equal to the
address of some function
that exists
and Function B would have the same
signature as the pointer that we
defined. Right.
And so they have to be the same.
Otherwise we'll get a compiler
warning saying that this function
takes different arguments than what
you've given it.
So let's look at some examples, so
we have a couple of different
functions here, we got print and
print B, so those are defined right
over here.
And you can notice that print a
prince eight times, returns eight
times A and print B
returns eight times eight times a
day. So we got A squared and A
cubed.
And then what it does is it prints
off and says into one four inch,
square inch or two, four
and cubed, and then here we're
doing a choice.
So here I've declared a function
pointer.
So we got into a pointer called
print.
It takes one integer as an argument.
And then you can see I just use
print as normal.
But inside of here it either does
choice one,
it does print A as the function
pointer or the address that it
assigns to print.
And down here. Print is then
assigned to the address of print
B and then we go ahead and use
our function as normal and we print
off the variable for that.
So here we can see that we have
our print assigning
for print equal to print A and print
B, and down here we can see
the pointers are
moved into EBP minus
twelve and so we can see that it
puts those offsets in there.
So it will do the calculation for
us on the fly.
And then we can see at the end when
it goes to call that function, so it
moves that pointer into
X and then does a call X.
So that's one way we can tell that
this is a function pointer as we're
going to see a call to a register
instead of the normal function that
we would normally see.
And so that's kind of giving us a
hint that it's a function point or
it's something that's dynamic where
the compiler cannot tell what
it should use for
that function. So it's dynamic in
nature.
So here's another example.
And so we have a 30 to bit function,
and so here I just give
that gave them into integers.
So I, I turn the address of
this function into an integer.
So I just figured out what that
was. And this is thirty two bit
and so an integer on thirty two bit
is the same as a pointer.
And so we're allowed to do that.
And then what we do is we print off
and we say, OK, here's the address
of a and here's the address of B,
we then read in a number from the
user so they're able to type one of
their choices.
And then what we do is we declare
a function pointer and we cast
it to the value that they
typed in so the user can actually
type in a number and that's the
function that it's actually going to
call.
And so here you can see a cast which
is wrapped around by parentheses.
And then we got our return type
isn't this is going to be a pointer
and it takes as an argument one
integer pointer.
So if this is a character, then this
would be a character right here.
And so then it gets going to call
that function again.
We're going to print off the result
to see what it is. And we have A and
B again for the squared and the
cubed.
So when you run this, it'll
basically print off addresses and
your machine might give you
completely different addresses,
but here's the address for a and
here's address for B.
And so if I type in that number
and hit enter, it'll read that
integer and then it'll actually call
that function.
Same thing for B, right.
So B has a different value.
I call that. I end up with it
running function B.
And so in our compiler, we can see
that it's going to go ahead and it's
going to load
those numbers into the variables
we got at 14 and at 16,
it's going to load the addresses of
our functions and functions be
right. We're going to go ahead and
print those off so that the user
knows what those are.
So you can see that those get
pushed on the stack as arguments.
We can see the further down
that EBP minus
twenty eight is going to be our
choice, and so then that
gets loaded into X,
right? And we then save it back into
20 for our function
pointer. So we're taking
the value of your choice and saving
it into TIFU, which is going to be
right here at 20.
And then when we go farther down,
we'll see the call to FU again
here, it's color coded
and we can see it loads of value
from EBP minus 20.
So that variable called FU
gets loaded into X and then we're
going to call the function X.
So again, we are dynamically calling
that function using
a register because we don't know
where it is.
So today we talked about function
pointers and see and we gave some
different examples of how we can
declare them and see and then use
them within our program
in a valid way.
And then we saw how that corresponded
with our assembly code.
So in the next lecture, we'll talk
about function pointers and we'll
give an example in assembly and show
how that works.
And then here's our quiz.
So given the following see function
signature for Fred,
how would you create a function
pointer for it?
So I gave it the name Ted, but you
have character, right, because
that's our first type, it's got
a pointer. So put parentheses around
my pointer here and then we have
double and car.
And so we pick all of the types out
of it and use that as our function
signature to create our function
pointer.
If you have questions, you can email
me Milham, Jay at you and Kadiatu
and you can find me on Twitter at
Milhouse 30.