C语言中能否将void指针强转为指定大小类型以替代scanf的switch分支?
你的强转思路不可行
你提到的(varSize *)dest强转方案在C语言中完全不成立:
- C是静态类型语言,指针类型必须在编译期确定,
varSize是size_t类型的数值,不能作为类型名用于强制类型转换,这段代码本身就无法通过编译。 scanf是可变参数函数,传入的指针类型必须和格式说明符严格匹配,否则会触发未定义行为,就算强行通过非常规方式转换指针,运行时也会出现类型匹配错误问题。
替代优化方案
方案1:查表法简化分支逻辑
如果还是想用函数实现,可以把格式符、对应格式串封装成查找表,比零散写case更易维护:
#include <stdio.h> #include <stdbool.h> #include <stdlib.h> typedef struct { char specifier; const char* fmt; } ScanFmtEntry; const ScanFmtEntry fmt_table[] = { {'d', " %d"}, {'s', " %29[^\n]"}, // 你原有代码多写了尾部的s,[^\n]本身就是完整格式符,加s会导致额外匹配输入中的s字符,大概率匹配失败 {'h', " %hd"}, {'f', " %f"}, }; void scan(char specifier, void *dest, const char* instruction, const char* error) { bool success = true; const char* fmt = NULL; // 查表匹配格式串 for(int i=0; i<sizeof(fmt_table)/sizeof(fmt_table[0]); i++) { if(fmt_table[i].specifier == specifier) { fmt = fmt_table[i].fmt; break; } } if(!fmt) abort(); // 非法格式符直接报错,可按业务需求调整逻辑 do { if(!success) { while (getchar()!='\n'); perror(error); } puts(instruction); success = scanf(fmt, dest); } while (!success); }
注:你的场景覆盖的4种类型,void作为可变参数传入时和对应类型指针的ABI兼容,不会出现适配问题*
方案2:用宏实现编译期类型推导(完全无分支)
如果可以接受用宏代替函数实现,还能省去手动传类型说明符的步骤,更易用:
#include <stdio.h> #include <stdbool.h> // 用C11 _Generic关键字编译期匹配类型对应格式串 #define SCAN_FMT(var) _Generic((var), \ int*: " %d", \ char*: " %29[^\n]", \ short*: " %hd", \ float*: " %f", \ double*: " %lf" \ ) #define scan(dest, instruction, error) do { \ bool success = true; \ do { \ if(!success) { \ while (getchar()!='\n'); \ perror(error); \ } \ puts(instruction); \ success = scanf(SCAN_FMT(dest), dest); \ } while (!success); \ } while(0)
使用时不需要传类型说明符,直接传变量指针即可:
int num; scan(&num, "请输入整数:", "输入不合法,请重新输入");
所有类型匹配逻辑都在编译期完成,无运行时开销,也不需要编写任何分支代码。
内容的提问来源于stack exchange,提问作者Alex Rosales
相关产品推荐
相关产品推荐

