c/test/minmax_api.c · 2181 字节 · 下载原文
/* minmax_api.c —— `min` / `max` 的**重名消歧**判据。
* minmax_api.c — criterion for the `min`/`max` de-duplication.
*
* ## 为什么单独立一个
* ## Why a dedicated probe
*
* `min` 这个名字在本仓有**三份**定义(`array.c` 收数组 / `math.c` 收两个 int / `builtins.c` 又一份),
* 而链接器对重名裸标签是**后链的赢、不报错** ⇒ `min(3, 5)` 有可能绑到数组版、
* 把 `3` 当成**数组指针**去解引用(`arr[0]` 读的是地址 3 处的内存)。
* 那种错编译期看不出来,运行时要么崩、要么给出一个"看着像个数"的垃圾。
*
* `The name `min` had three definitions; the linker silently picks one. If it picks the array
* version, `min(3, 5)` dereferences address 3.`
*
* 2026-10-08 消歧:数组版统一叫 `*_arr`(`statistics.c` 的 `min_arr`/`max_arr`/`sum_arr`),
* 两个 int 的版本统一在 `math.c`。本探针钉住的就是"**`min(3,5)` 必须得 3**"。
*
* ## 判据
* ## Criteria
*
* 全部是**能分辨"绑错版本"**的取值:数组版拿到 `(3, 5)` 会去读地址 3 处的 `arr[0]`,
* 结果与 `3` 无关(多半崩或给个垃圾),**不可能**恰好等于 3。
*
* 跑法(桌面,秒级):
* dotnet scripts/vmlcli/bin/Release/net10.0/vmlcli.dll third_party/vml/Examples/c/test/minmax_api.c
*/
int min(int a, int b);
int max(int a, int b);
int fails = 0;
void ck(char* name, int got, int want) {
if (got == want) {
printf("OK %s = %d\n", name, got);
} else {
printf("FAIL %s: got %d, want %d\n", name, got, want);
fails = fails + 1;
}
}
int main(void) {
/* ⚠ 这些取值都"不像指针"(3 / 5 / -7 都不是有效地址),所以一旦绑错版本就会现形 */
ck("min(3,5)", min(3, 5), 3);
ck("max(3,5)", max(3, 5), 5);
ck("min(-1,-7)", min(-1, -7), -7);
ck("max(-1,-7)", max(-1, -7), -1);
ck("min(0,0)", min(0, 0), 0);
ck("max(7,7)", max(7, 7), 7);
printf("MINMAX_API %s (fails=%d)\n", fails == 0 ? "PASS" : "FAIL", fails);
return fails;
}