abdullah kahraman
abdullah kahraman

Reputation: 503

What does this pointer do in the argument of this function?

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?

enter image description here

Upvotes: 1

Views: 144

Answers (3)

James
James

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

Evan Teran
Evan Teran

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

user1417475
user1417475

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

Related Questions