Reputation: 503
I am an electronics guy so, treat me well, please.
I was reading this article about real time operating systems for 8-bit microcontrollers. I came across this function with a weird looking argument. I could not understand what it is doing. I know that void
means "no type". I am guessing that (*Task)
is the casting. I really have no idea what those brackets do after that.
What does this function's argument include?
Also, I couldn't understand what does *(int*)((NewTCB->Stack) + (STACK_DEPTH-2)) = (int)Task;
do?
Upvotes: 1
Views: 144
Reputation: 9288
Evan Teran's answer is correct. I'd expand on it by saying that from the code it seems to be a pointer to the function that's executed when the task is selected to be run.
As for *(int*)((NewTCB->Stack) + (STACK_DEPTH-2)) = (int)Task;
I assume in your environment int
is 16 bits? If so this would be the -2. This code saves the address of the Task's 'main' function in this structure (which is weird because it's already saved in the ->Task
member, but there's probably a good reason)
Upvotes: 0
Reputation: 90563
void (*Task)()
is actually a function pointer. Basically it is saying: "the parameter name is Task
and it is a function which returns void
and (since this is c not c++) takes any number of arguments.
So you could call it like this:
void my_task() {
/* do something */
}
TaskCreate(my_task);
Of course, it would also be safe to write void my_task(void) {
as well. When coding c, I personally prefer to explicitly say "there are no parameters"
Finally, *(int*)((NewTCB->Stack) + (STACK_DEPTH-2)) = (int)Task;
is doing some casting magic.
Let's disect it:
(int)Task
is first converting Task
to an int
(which is questionable, but probably ok for your particular architecture/OS. Personally, I would use a long
to be safe).
((NewTCB->Stack) + (STACK_DEPTH-2))
is just doing some simple arithmetic on NewTCB->Stack
to get a pointer to a location in the TCB
's stack.
*(int*)
says "convert this to an int *
and then deference (read or write) the location it points to.
We could write this more simply as follows:
int f = (int)Task;
int s = ((NewTCB->Stack) + (STACK_DEPTH-2)); /* I don't know the type of `NewTCB->Stack`, so we'll pretend 'int' for now */
int *stack_ptr = (int*)s;
*stack_ptr = f;
which is probably more clear.
FOLLOW UP: I'd like to point out how I use tend to use function pointers since the syntax can be a bit confusing sometimes. And I find this approach to be very helpful. Basically I like to create a typedef
for the function pointer and use that instead, I find it a lot easier to get right:
For example:
/* typedef func_t to be a pointer to a function taking no arguments and returning void */
typedef void (*func_t)(void);
Then later...
void CreateTask(func_t task) {
/* same work as your example, just a little easier to read */
}
Upvotes: 7
Reputation: 236
*(int*)((NewTCB->Stack) + (STACK_DEPTH-2)) = (int)Task;
takes Task
and converts it to an integer. Then, it finds NewTCB
's stack (some form of an array). It takes that stack and finds the penultimate member. It then treats that as the address of an integer variable and assigns the converted Task to the variable at that address.
NewTCB->stack
uses C++ pointer-to-member syntax. NewTCB
is a pointer to a TCB
object, and TCB
objects evidently have a Stack property.
Adding STACK_DEPTH - 2
to it is the same as writing (NewTCB->Stack)[STACK_DEPTH - 2]
(in plaintext: NewTCB->Stack
: get object at index STACK_DEPTH - 2
) except that the stack object is a dynamically assigned array.
If NewTCB->Stack
has length STACK_DEPTH
, then the object at index STACK_DEPTH - 2
is the penultimate member (0-based indices).
The rest just handles conversions necessary to move Task to the appropriate spot.
Upvotes: 0