You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:22:24