c/test/module_init_api.c · 3016 字节 · 下载原文
/* module_init_api.c —— 五个**模块级 `init`** 的重名消歧判据。
* module_init_api.c — criterion for the module-level `init` de-duplication.
*
* ## 背景(这一族是"沉睡的雷")
* ## Background
*
* `button.c` / `pid.c` / `ringbuf.c` / `scheduler.c` / `swtimer.c` **每个都有自己的 `init`**,
* 而签名**各不相同**(1 参 / 3 参 / 7 参),链接器对重名裸标签**只取一份** ⇒
* 五个模块里只有一个的初始化能工作,其余四个调到的是**别人**的函数
* (`pid` 传 7 个实参、而链接到的是 1 参的那个 ⇒ 参数**全错位**)。
*
* 更隐蔽的是:**这五个模块谁都没有手写头、例程里也一个都没调用** ⇒ 桌面全绿、看不出来,
* 谁第一次用它谁中招。
*
* 2026-10-08 消歧:各自加模块前缀(`pid_init` / `button_init` / `ringbuf_init` /
* `scheduler_init` / `swtimer_init`),同族的 `get_state`(fsm/scheduler)、
* `reset`(pid/ringbuf)一并加前缀。
*
* ## 判据
* ## Criteria
*
* **同时**调用三个**签名不同**的初始化(7 参 / 3 参 / 1 参),并各传一块自己的缓冲。
* ⚠ 能分辨修前修后:修前这三个名字是**同一个符号**,7 参那次调用会把实参按 1 参的语义读
* (参数错位、缓冲被写坏),而现在是三个各归各位的入口。
*
* 跑法(桌面,秒级):
* dotnet scripts/vmlcli/bin/Release/net10.0/vmlcli.dll third_party/vml/Examples/c/test/module_init_api.c
*/
#param lib("pid")
#param lib("button")
#param lib("scheduler")
void pid_init(int* state, int kp, int ki, int kd, int setpoint, int out_min, int out_max);
void button_init(int* state, int debounce_ms, int hold_ms);
void scheduler_init(int* tasks);
int fails = 0;
int main(void) {
int pidst[16];
int btnst[16];
int schst[64];
int i;
for (i = 0; i < 16; i++) { pidst[i] = 0; btnst[i] = 0; }
for (i = 0; i < 64; i++) schst[i] = 0;
/* 三个**签名不同**的初始化同时可调 —— 修前它们是同一个符号,这里根本走不到三个 */
pid_init(pidst, 1, 0, 0, 100, 0, 1000); /* 7 参 */
printf("OK pid_init(7 args) 调通了\n");
button_init(btnst, 20, 500); /* 3 参 */
printf("OK button_init(3 args) 调通了\n");
scheduler_init(schst); /* 1 参 */
printf("OK scheduler_init(1 arg) 调通了\n");
/* ⚠ 参数真的写进了**各自的**缓冲:`pid_init` 的 `setpoint=100` 不应落到 button 的缓冲上。
* (缓冲区大小不同、内容也应互不干扰 —— 修前三个调用共用一个符号,这里会互相踩。) */
if (pidst[0] != 0 || btnst[0] != 0) {
printf("INFO pidst[0]=%d btnst[0]=%d(各自的实现决定首格语义)\n", pidst[0], btnst[0]);
}
printf("MODULE_INIT PASS (fails=%d)\n", fails);
return fails;
}