C++中SQLite3查询结果char*转uint16/uint32异常求助
问题根源分析
你遇到的问题核心在于:sqlite3 查询返回的 char** argv 中的每一项都是文本字符串,并非二进制数值。你直接把 argv[1] 和 argv[2] 强制转换成 uint16_t*、uint32_t* 去解引用,本质是把字符串的字节内容当成了整数的二进制表示,这自然会得到随机的错误值。
举个例子:假设 argv[1] 是字符串 "123",它在内存中的字节是 0x31 0x32 0x33 0x00,你强制转成 uint16_t* 后解引用,取的是前两个字节 0x3231(十进制12849),这显然不是你要的123。
而 type 看起来正常,大概率是因为你存的是单个字符(比如 "1"),*(argv[0]) 取的是字符的ASCII码,刚好和你预期的数值匹配;name 直接赋值字符串是对的,因为它本身就是文本类型。
修正方案
你需要把字符串形式的数值转换成对应的整数类型,用标准库的字符串转整数函数就能解决这个问题,比如 strtoul(处理无符号整数更安全)或者 C++11 后的 std::stoul。
修正后的转换函数如下:
#include <cstdlib> // 用于 strtoul #include <stdexcept> // 可选,用于错误处理 #include <cstdint> // 确保 UINT16_MAX、UINT32_MAX 可用 void SqlToRow(char **argv, Row *row){ // 转换type:如果存的是字符形式(比如"1"),可以保留原方式;如果是数值字符串,建议转成整数 // 比如如果type存的是数值"1",应该写成:row->type = static_cast<uint8_t>(strtoul(argv[0], nullptr, 10)); row->type = *(argv[0]); // 转换user:将字符串转成uint16_t unsigned long user_val = strtoul(argv[1], nullptr, 10); if (user_val > UINT16_MAX) { throw std::out_of_range("User value exceeds uint16_t limit"); } row->user = static_cast<uint16_t>(user_val); // 转换ipAddress:将字符串转成uint32_t unsigned long ip_val = strtoul(argv[2], nullptr, 10); if (ip_val > UINT32_MAX) { throw std::out_of_range("IP address value exceeds uint32_t limit"); } row->ipAddress = static_cast<uint32_t>(ip_val); // name直接赋值字符串 row->name = argv[3]; }
额外注意事项
- 如果你的IP地址是点分十进制格式(比如
"192.168.1.1"),上面的方法还不适用,需要额外的解析逻辑(比如用inet_addr或者自己拆分字符串转成32位整数)。 - 建议添加空指针检查:比如判断
argv的每个元素是否为nullptr,避免空指针解引用;同时可以通过strtoul的第二个参数判断字符串是否为合法数字,处理转换失败的情况。 - 对于
type字段,如果实际存储的是数值(而非字符),最好也用字符串转整数的方式,避免依赖ASCII码的巧合导致后续出现隐藏问题。
内容的提问来源于stack exchange,提问作者ICU_
相关产品推荐
相关产品推荐

