我觉得你的问题很有趣,因为它最初看起来微不足道,但在获得答案的过程中提出了很多问题。
我假设您想将一个 64 位整数从 C++ 传递到 QML。我稍后会解释原因。
64 位整数的 QML 基本类型
没有 64 位整数 QML basic type,因此您不能期望您的 C++ 值被转换并存储在这种不存在的 QML 类型属性中。如文档中所述,Qt 模块可以扩展可用类型的列表。我们甚至可以想到未来我们可以添加自己的类型,但现在不行:
目前只有 Qt 提供的 QML 模块可以提供它们的
自己的基本类型,但是这可能会在 Qt QML 的未来版本中发生变化。
人们可能认为在 64 位平台上编译他们的应用程序应该可以完成这项工作,但这不会改变任何事情。关于这个问题有a lot of answers。为了清楚起见,这里是在同一台计算机上使用 32 位和 64 位编译器的结果比较:
在使用 32 位编译器 (mingw53) 的 64 位系统(Windows 7 64 位)的计算机(64 位处理器:Core i7)上,我有
4 = sizeof(int) = sizeof(long) = sizeof(int*) = sizeof(size_t)
我已经把size_t 明确表示它不能用来表示文件大小,它不是its purpose。
使用 64 位编译器(msvc2017、x64),在同一系统上:
4 = sizeof(int) = sizeof(long)
8 = sizeof(int*) = sizeof(size_t)
使用 64 位编译器不会改变 sizeof(int),因此认为 int 与 int* 大小相同显然是错误的。
在您的情况下,您似乎想要存储文件大小,而 32 位不足以表示文件的大小。所以如果我们不能依靠int 来做,应该使用什么类型?
文件大小类型大小
目前,我假设 64 位整数应该足够了,并且是存储文件大小的正确方法。但这是真的吗?根据 cplusplus.com,此类型为 std::streampos。如果您在 cppreference.com 上查找详细信息,您会发现 std::streampos 是 std::fpos 的专门化及其典型实现的描述:
类模板std::fpos的特化标识绝对
流或文件中的位置。 fpos 类型的每个对象都包含
流中的字节位置(通常作为类型的私有成员
std::streamoff) 和当前班次状态,State 类型的值
(通常是std::mbstate_t)。
std::streamoff 的实际类型可能是一个 64 位有符号整数:
std::streamoff 类型是一个足够大小的有符号整数类型
表示操作所支持的最大可能文件大小
系统。通常,这是 typedef 到 long long。
此外,在同一页面中,您可以阅读:
std::fpos 类型的值可以隐式转换为std::streamoff(转换结果是从开头的偏移量
文件)。
std::fpos 类型的值可从std::streamoff 类型的值构造
让我们看看我们拥有什么,再次取决于 32 位或 64 位目标平台。
使用我拥有的 32 位编译器
8 = sizeof(long long) = sizeof(std::streamoff)
16 = sizeof(std::streampos)
这表明,显然,比当前了解文件大小所需的更多信息存储在std::streampos 中。
使用 64 位编译器,在同一系统上:
8 = sizeof(long long) = sizeof(std::streamoff)
24 = sizeof(std::streampos)
sizeof(std::streamoff) 的值没有改变。它可能有。在这两种情况下,它都必须足够大才能存储文件大小。您可能希望使用std::streamoff 在 C++ 端存储文件大小。你不能依赖它是 64 位的。
假设有人想冒险假设它是 64 位的,如这些示例所示:仍然存在将其作为基本类型传递给 QML 甚至可能传递给 Javascript 引擎的问题。
不过在 QML 中使用接近 64 位
如果您只需要将大小显示为以字节为单位的数字,则需要在 UI 中使用文本表示。您可以坚持这个想法,使用字符串,而忘记传递整数值。
如果您需要在 QML 端使用 Javascript 进行算术运算,除非您不使用核心语言进行算术运算,否则您可能会点击 Javascript Number 的 53 bit barrier。
在这里,如果您假设文件大小不能大于 2^53,那么使用 double 可以工作。您必须知道double 类型在您的目标平台上是如何处理的,如this answer 中所述,如果您足够幸运,它将具有相同的能力来无损失地存储 53 位整数值。之后您可以直接在 Javascript 中对其进行操作,并且保证可以工作,至少在 ECMA 262 版本 8 中是这样。
现在可以了吗?我们可以对小于 2^53 的任何文件大小使用双精度吗?
嗯……Qt不一定实现ECMAScript的最新规范,使用several implementations。
在 Webviews 中,它确实使用了rather common implementation。
在 QML 中,它使用自己的、未记录的、内置的 Javascript 引擎,基于 ECMA 262 第 5 版。这个版本的 ECMA 没有明确提到一个值,所有较小的整数值都保证存储在 Number 中。这并不意味着它不会工作。即使已经提及,实施也只是基于规范,并不要求合规。你可能会发现自己很不幸地让它工作了很长时间,然后在更新的 Qt 版本中发现它不再工作了。
看起来需要做出很多假设。在基于它的软件的整个生命周期中,所有这些都可能并且可能保持真实。所以这是一个处理风险的问题。
有没有办法降低想要这样做的人的风险?
不冒一点正确性的风险
我看到了两条主要路径:
- 根本不关心这些东西。例如,使用双精度,只要它看起来有效,就可以做任何你想做的事情。如果它不适用于没有发生的情况,为什么要尝试处理它们?当它不起作用时,你会处理它。
- 努力做到严谨,并以更稳健的方式做到这一点。据我了解,这种解决方案可能是将所有文件大小算法保留在 C++ 端,并仅将安全值传递给 QML 端。例如用于测试的布尔值和用于显示尺寸值的字符串(总尺寸、剩余尺寸……)。您无需担心任何事物中有多少位。
提示:bittorent protocol 使用字符串来编码大小。
问题不仅限于 QML 属性
如果您使用 Javascript 处理带有 Number 实例的整数值,并将其用作 QML 信号的 int 参数的参数,则可能会出现同样的问题。例如,声明这样的信号:
signal sizeChanged(var newSize) // Number class (maybe 53 bit) integral value possible
可以处理以下肯定不能处理的情况:
signal sizeChanged(int newSize) // 32 bit int limitation
失败的一个例子是通过(new Date()).getTime()。
这与 C++ 属性与 QML 交互的限制相同。