我是一个电子人,所以请善待我。
我正在阅读这篇关于 8 位微控制器的实时操作系统的文章。我遇到了这个函数,有一个看起来很奇怪的论点。我无法理解它在做什么。我知道这void
意味着“没有类型”。我猜这(*Task)
就是选角。我真的不知道那些括号在那之后做了什么。
这个函数的参数包括什么?
另外,我不明白它是*(int*)((NewTCB->Stack) + (STACK_DEPTH-2)) = (int)Task;
做什么的?
void (*Task)()
实际上是一个函数指针。基本上它是在说:“参数名称是Task
,它是一个返回的函数,void
并且(因为这是 c 而不是 c++)接受任意数量的参数。
所以你可以这样称呼它:
void my_task() {
/* do something */
}
TaskCreate(my_task);
当然,写起来也是安全的void my_task(void) {
。在编码c时,我个人更喜欢明确地说“没有参数”
最后,*(int*)((NewTCB->Stack) + (STACK_DEPTH-2)) = (int)Task;
正在做一些施法魔法。
让我们剖析一下:
(int)Task
首先转换Task
为int
(这是有问题的,但对于您的特定架构/操作系统可能没问题。就个人而言,我会使用 along
以确保安全)。
((NewTCB->Stack) + (STACK_DEPTH-2))
只是在做一些简单的算术运算以获取指向堆栈NewTCB->Stack
中某个位置的指针。TCB
*(int*)
说“将其转换为一个int *
然后尊重(读取或写入)它指向的位置。
我们可以更简单地写如下:
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;
这可能更清楚。
跟进:我想指出我如何使用倾向于使用函数指针,因为语法有时会有点混乱。而且我发现这种方法非常有帮助。基本上我喜欢typedef
为函数指针创建一个并使用它,我发现它更容易正确:
例如:
/* typedef func_t to be a pointer to a function taking no arguments and returning void */
typedef void (*func_t)(void);
然后后来...
void CreateTask(func_t task) {
/* same work as your example, just a little easier to read */
}
*(int*)((NewTCB->Stack) + (STACK_DEPTH-2)) = (int)Task;
接受Task
并将其转换为整数。然后,它找到NewTCB
' 堆栈(某种形式的数组)。它采用该堆栈并找到倒数第二个成员。然后它将其视为整数变量的地址,并将转换后的 Task 分配给该地址处的变量。
NewTCB->stack
使用 C++ 成员指针语法。 NewTCB
是指向TCB
对象的指针,而TCB
对象显然具有 Stack 属性。
添加STACK_DEPTH - 2
到它与写入相同(NewTCB->Stack)[STACK_DEPTH - 2]
(以纯文本::NewTCB->Stack
get object at index STACK_DEPTH - 2
),除了堆栈对象是动态分配的数组。
如果NewTCB->Stack
有 length STACK_DEPTH
,则 index 处的对象STACK_DEPTH - 2
是倒数第二个成员(从 0 开始的索引)。
其余的只是处理将 Task 移动到适当位置所需的转换。
埃文·特兰的回答是正确的。我会扩展它,从代码中它似乎是一个指向在选择运行任务时执行的函数的指针。
至于*(int*)((NewTCB->Stack) + (STACK_DEPTH-2)) = (int)Task;
我假设在您的环境int
中是 16 位?如果是这样,这将是-2。这段代码在这个结构中保存了任务的'main'函数的地址(这很奇怪,因为它已经保存在->Task
成员中,但可能有一个很好的理由)