为什么在 SQLite DB 中存储一个 32 位无符号整数值 -1 并读回它会导致该值变为一半?
Why does storing an 32-bit unsigned int value of -1 in SQLite DB and reading it back result in the value getting changed to half?
下面是问题的最简单形式的伪代码:
enum E { VALUE = -1; }
uint32_t value = VALUE; // signed to unsigned conversion without typecasting
SQLiteDB.INSERT(<table containing `value`>);
SQLiteDB.SELECT(<same table as above>);
在数据库中,我看到 value
存储为 4294967295
(即 0xFFFFFFFF
),这是正确的。但是当从数据库中读取值时,它被截断为 2147483647
(0x7FFFFFFF
),这是原始值的大约一半。
这是为什么?如何解决这个问题?
Update:如上所述,值 0xFFFFFFFF 在 SQLite 中是正确可见的,但在 uint32_t
中读取时,它被截断了。可能是数据丢失?
下面是在实际数据上使用 SQLiteBrowser 看到的图像。
相关但不重复:
- Casting negative integer to larger unsigned integer
- What happens if I assign a negative value to an unsigned variable?
发现问题。
我正在使用库代码来读取数据库表。正确获取字符串形式的值。此外 std::stoi()
用于转换为所需的 uint32_t
.
现在 4294967295
对于 std::stoi()
来说 太大 了。事实上在 Ubuntu 64 位机器上,它会抛出异常。然而在 Windows 中,它以某种方式通过将符号位重置为 0 来截断,因此它变成了 2147483647
。可能这是一个一致的未定义行为。 :-)
而不是 std::stoi()
,如果我们使用 std::stol()
或 ::strtoul()
,那么问题就解决了,值被正确读取为 4294967295
到 uint32_t
变量。
下面是问题的最简单形式的伪代码:
enum E { VALUE = -1; }
uint32_t value = VALUE; // signed to unsigned conversion without typecasting
SQLiteDB.INSERT(<table containing `value`>);
SQLiteDB.SELECT(<same table as above>);
在数据库中,我看到 value
存储为 4294967295
(即 0xFFFFFFFF
),这是正确的。但是当从数据库中读取值时,它被截断为 2147483647
(0x7FFFFFFF
),这是原始值的大约一半。
这是为什么?如何解决这个问题?
Update:如上所述,值 0xFFFFFFFF 在 SQLite 中是正确可见的,但在 uint32_t
中读取时,它被截断了。可能是数据丢失?
下面是在实际数据上使用 SQLiteBrowser 看到的图像。
相关但不重复:
- Casting negative integer to larger unsigned integer
- What happens if I assign a negative value to an unsigned variable?
发现问题。
我正在使用库代码来读取数据库表。正确获取字符串形式的值。此外 std::stoi()
用于转换为所需的 uint32_t
.
现在 4294967295
对于 std::stoi()
来说 太大 了。事实上在 Ubuntu 64 位机器上,它会抛出异常。然而在 Windows 中,它以某种方式通过将符号位重置为 0 来截断,因此它变成了 2147483647
。可能这是一个一致的未定义行为。 :-)
而不是 std::stoi()
,如果我们使用 std::stol()
或 ::strtoul()
,那么问题就解决了,值被正确读取为 4294967295
到 uint32_t
变量。