我正在使用 Visual Studio 编译器在 Windows 上进行 C++ 开发,特别是 Visual Studio 2015 Update 3。
对于一些与 DSP 相关的工作,我正在使用 unsigned int/unsigned long 数据类型。我想知道这两个内置的 C/C++ 类型之间有什么区别。
我通过 Google 和 SO 搜索了一下,找到了这些引用资料。
- Types documentation在 cppreference.com 上
- Types documentation在 MSDN for Visual Studio 2015 上
- Types documentation对于 GNU C/C++(因为 G++ compiler 指出 C/C++ 使用相同的默认类型实现,我在这里引用 C 文档)
我假设 cppreference 文档是 ISO C++11 标准的总结。因此,根据 LP/ILP 32/64 数据模型,“标准”unsigned 和 unsigned int 是 16/32 位,而 unsigned long 和unsigned long int 是 32/64 位,具体取决于 LP/ILP 32/64 数据模型。
对于 MSDN 和 GNU 文档,它们都声明 unsigned int/unsigned long 正在使用 32 位实现并且最多可以保存 4,294,967,295 的值。但是 GNU 文档还指出,根据您的系统,unsigned long 可以是 64 位,它与 unsigned long long int 相同。
所以我的问题如下:
- 对于 unsigned long 64 位,超出上限 4,294,967,295 是未定义行为还是正确行为?
- 如果我有一个在 Visual Studio 中编译的 Windows 系统上运行的应用程序,则基本 unsigned == unsigned long。对还是错?
- 如果我有一个由 GNU 编译器在 Linux/Windows 上编译的应用程序,我必须确定 unsigned long == unsigned int 或 unsigned long == unsigned long long 以避免数据溢出。对或错
- 如果我有一个可能由所有这些 Visual Studio/GNU/Clang/Intel 编译器编译的跨平台应用程序,我必须使用一堆预处理器对环境进行明确分类,以避免数据溢出。对或错
提前致谢。
编辑: 感谢@PeterRuderman 指出无符号类型的超出 ceil 值不是未定义的行为。
那么我的问题1会变成:
- 对于 unsigned long 64 位,超出上限 4,294,967,295 是否会导致自身回绕?
最佳答案
简短的回答是,是的,sizeof(unsigned)
不保证等于 sizeof(unsigned long)
但它恰好在 MSVC 中。如果您需要以独立于平台的方式确定地知道整数的大小,请使用 <cstdint>
中的类型: uint32_t
和 uint64_t
.避免 long
在可移植代码中,它会导致很多令人头疼的问题。
另请注意,无符号 整数溢出不是未定义的行为。定义的行为是值回绕。 (例如 std::numeric_limits< uint64_t >::max() + 43 == 42
)。对于溢出是未定义行为的signed 类型而言,情况并非如此。
要回答您的最后一个问题,64 位整数可以存储 [0, 264 - 1] 范围内的值。 232 + 1 不会导致环绕。
关于unsigned int 和 unsigned long int 之间的 C++ 区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43403613/