无符号长整型与无符号长长整型(从可移植性角度看)

14
我想在我的项目中使用大正整数(8字节),尽管在我的系统中sizeof(unsigned long)的结果为8,但我知道在大多数系统中unsigned long只有4个字节,因此我决定尝试使用unsigned long long,因为它保证至少有8个字节。
然而,随着我使用它的次数增多,我发现它并不是非常便携,例如在某些系统(取决于编译器),printf格式为%llu,在某些系统中则为%lld。
我的代码只能在64位debian机器上运行,在那里unsigned long将会是8个字节。可移植性并不是一个很大的问题。在这种情况下使用unsigned long long超过unsigned long是否过头了?在使用unsigned long long而不是unsigned long时是否有其他好处?

9
你尝试过使用uint64_t吗?它在<stdint.h>头文件中。 - Mysticial
使用它相比于unsigned long long有什么优势? - erin c
3
如果你在C++11中没有任何精确为64位的类型,long long和longer type都会停止编译。这两种类型在C++11中都有,但在此之前通常作为扩展存在,不过如果其中一种类型有时存在而另一种类型不存在,我也不会感到惊讶。如果没有这些类型,使用stdint.h更容易模拟(假设该类型存在),而不是使用long long。 - AProgrammer
谢谢,我会考虑使用它。 - erin c
这里有一个相关的问题:https://dev59.com/YGkw5IYBdhLWcg3wNX73. - juanchopanza
3个回答

23

unsigned long long 无论在哪个平台上都保证至少有64位,(有些平台它可能会更多,比如我知道的有72位和96位的,但这些平台很少见且相当奇特)。unsigned long 至少保证有32位。如果你需要超过32位的数值,我会建议使用 unsigned long long

关于格式方面,对于 printf 函数,你应该使用 "%llu"(因为它是无符号数);而 "%lld" 则适用于 signed long long


谢谢James,我也是这么想的,使用unsigned long long肯定更安全。但问题在于,由于我的开发和目标环境中unsigned long是8个字节,我能否只使用unsigned long呢?顺便说一下,当我使用%llu与unsigned long long一起使用时,编译器会抛出警告,这种不可移植性让我不敢使用unsigned long long。 - erin c
“至少64位”保证不是只有在C++11之后才有的吗? - juanchopanza
@juanchopanza 官方上说,在 C++11 之前,C++ 并没有 long long。不过,C90 中有,并且要求至少为 64 位。微软曾经一度使用 __int64(认为 long long 是 Unix 的专用术语,直到 C90 将其正式纳入标准),但现在已经支持 long long 很长时间了。即使在 C90 之前,long long 起源的 Unix 平台也都要求它至少为 64 位。 - James Kanze
1
@JamesKanze 我很好奇 - 有哪些平台使用72或96位? - jarmond
1
@jarmond Unisys有(或者至少曾经有过)一台36位字长的机器。Unisys还有(我认为仍然有)一台48位字长的机器。由于“long long”必须至少有64位,因此您只能使用2个字。 (顺便说一句:36位机器也是1的补码,而48位机器是带符号的幅值,保留8位。这当然使它们与通常的东西不同。) - James Kanze
显示剩余2条评论

1

如果您想要保持长时间的稳定性,您可以这样做:

#include <limits.h>
#if ULONG_MAX >= 0xFFFFFFFFFFFFFFFFULL
typedef unsigned long uint64;
#else
typedef unsigned long long uint64;
#endif

关于此事

在某些系统中(取决于编译器),printf使用%llu格式,而在其他一些系统中则使用%lld格式。

printf()不会猜测格式。您需要告诉它格式。

如果要打印上述定义的uint64,请按以下方式执行:

printf("%llu", (unsigned long long)some_uint64_value);

您可以typedef unsigned long long ulonglong;使转换更容易输入。

确实存在其他执行相同操作的方法,但并非所有编译器都支持它们。这就是我附加ULL后缀到数字的原因。在C89和C99之间的某些兼容模式中,0xFFFFFFFFFFFFFFFF可能被解释为unsigned long而不是unsigned long long,并且将被截断。最新的gcc默认以gnu89模式运行C代码,而不是c99或更高版本。


0
如果您需要确保整数值的固定大小独立于平台,可以使用boost::integers库(请参见此处)。您可以使用boost::int64_t或boost::uint64_t来表示无符号值。

3
为什么要使用Boost库而不是stdint.h中的uint64_t类型? - WeaselFox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接