【发布时间】:2021-11-09 06:15:53
【问题描述】:
我试图通过将数据类型隐藏在void* 后面并将其转换为%d 的含义(即, int*):
#include <stdio.h>
#include <stdint.h>
int main()
{
int8_t a, b;
void *v[2] = { &a, &b };
sscanf("-111,9\n", "%d,%d", (int*)v[0], (int*)v[1]);
printf("Works : %d, %d\n", a, b);
printf("Doesn't: %d, %d\n\n", *(int*)v[0], *(int*)v[1]);
return 0;
}
这是输出:
Works : -111, 9
Doesn't: 0, 9
问题:
- 为什么
scanf()被a和b的直接printf验证,在转换为int*时可能读入8 位类型?不应该超限吗? - 相反,为什么
printf()无法打印被取消引用为*(int*)v[0]的 8 位类型,而 scanf 可以读入它们? - 由于格式说明符无疑是不够的,因此是否有一些编译器时间魔法可以告诉 scanf/printf 数据类型是什么?
我知道这段代码可能是错误的,但我仍然对示例背后的细节感到好奇。
感谢您的帮助!
【问题讨论】:
-
scanf不知道它的参数是什么类型:stackoverflow.com/questions/18203636/… -
@Dai,由于取消引用,printf 核心转储,我认为这是正确的行为,因为 char 太小而无法读取为超出堆栈的 int,这可能是您看不到的原因它。但是scanf如何在不破坏堆栈的情况下将32位int(“%d”)写入8位类型?
-
你得到了 UB,因为 scanf 在对象的范围之外写入
-
这是未定义的行为,因此没有必要推测它。
-
"sscanf("-111,9\n", "%d,%d", &a, &b); 不会给出编译器警告," 如果启用编译器警告,它会:@ 987654322@.