unsigned int和unsigned long int

时间:2017-04-14 00:26:18

标签: c++ visual-studio gcc g++

我正在使用Visual Studio Compiler在Windows上进行C ++开发,特别是Visual Studio 2015 Update 3。

对于某些与DSP相关的工作,我使用 unsigned int / unsigned long 数据类型。我想知道这两个内置的C / C ++类型有什么区别。

我通过Google和SO搜索了一下,发现了这些参考资料。

    cppreference.com上的
  1. Types documentation
  2. 在Visual Studio 2015的MSDN上
  3. Types documentation
  4. Types documentation对于GNU C / C ++(因为G++ compiler声明C / C ++使用相同的默认类型实现,我在这里引用C doc)
  5. 我认为cppreference文档是ISO C ++ 11标准的总结。所以来自"标准" 无符号 unsigned int 为16/32位,具体取决于LP / ILP 32/64数据模型,而 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相同。

    所以我的问题如下:

    1. 对于无符号长64位,超出上限4,294,967,295的未定义行为或正确行为?
    2. 如果我的应用程序在Visual Studio中编译的Windows系统上运行,则basicall 无符号 == 无符号长。对错吗?
    3. 如果我有一个在Linux / Windows上运行的GNU编译器编译的应用程序,我必须确定 unsigned long == unsigned int unsigned long < / strong> == unsigned long long 以避免数据溢出。对错
    4. 如果我有一个可能由所有这些Visual Studio / GNU / Clang / Intel编译器编译的跨平台应用程序,我必须使用一堆预处理器清楚地对环境进行分类,以避免数据溢出。对错
    5. 提前致谢。

      修改 感谢@PeterRuderman指出超出无符号类型的ceil值并不是未定义的行为。

      然后我的问题1将改为:

      1. 对于无符号长64位,超出上限4,294,967,295会导致自身缠绕吗?

2 个答案:

答案 0 :(得分:2)

简短的回答是,sizeof(unsigned)不能保证等于sizeof(unsigned long),但确实恰好在MSVC中。如果您需要以独立于平台的方式确定整数的大小,请使用<cstdint>uint32_tuint64_t中的类型。在可移植代码中避免使用long,这会导致很多麻烦。

另请注意,溢出 unsigned 整数不是未定义的行为。定义的行为是值环绕。 (例如std::numeric_limits< uint64_t >::max() + 43 == 42)。对于签名的类型,情况并非如此,其中溢出是未定义的行为。

要回答最后一个问题,64位整数可以存储[0,2 64 - 1]范围内的值。 2 32 + 1不会导致环绕。

答案 1 :(得分:1)

在C ++标准中,unsigned int仅保证能够表示从065535的值。实际上,这相当于16位。实现(即编译器)可以为unsigned int提供更大的范围,但不是必需的。

相比之下,unsigned long int可以保证能够代表04294967295范围内的值。实际上,这相当于32位。同样,实现可能支持更大的范围。

这些类型的范围和大小是实现定义的。实施必须满足最低要求,并选择其选择的文件。

实现提供32位的unsigned intunsigned long int并不罕见。或者,一个或两个是64位。如您所述,Visual Studio 2015的文档指出unsigned intunsigned long int都代表04294967295的值。

对于像g ++这样可以针对一系列系统的编译器,选择通常由目标系统决定。因此,对于32位系统,g ++的构建可能支持unsigned long的不同范围,而不是64位系统的构建。

回答你的问题

  

对于无符号长64位,超出上限4,294,967,295的未定义行为或正确行为?

虽然它可能无法产生您期望的结果,但它具有良好定义的行为。 C ++中的无符号整数类型使用模运算。将转换超出04294967295范围的整数值(可支持更大范围的类型),使其在该范围内(数学上等效于重复加或减{{1 } [注意最后一位数])。换句话说,它将“环绕”。

  

如果我有一个在Visual Studio中编译的Windows系统上运行的应用程序,则basicall unsigned == unsigned long。对错吗?

假设Visual Studio 2015确实如此,正如您链接的文档所述。未来的Microsoft产品可能会或可能不会 - 这是一个实施决策。

  

如果我有一个在Linux / Windows上运行的GNU编译器编译的应用程序,我必须确保无符号long == unsigned int或unsigned long == unsigned long long以避免数据溢出。对错

实际上是假的。

只有在移植依赖于这些假设的代码时才会出现这种情况。

您可以使用某些技术,因此您的代码不依赖于此类假设。例如,您可以安全地检测涉及两个4294967296值的操作何时溢出或下溢,并采取措施以产生所需的结果。如果适当地检查了所有操作,则可以避免依赖特定大小的类型。

  

如果我有一个可能由所有这些Visual Studio / GNU / Clang / Intel编译器编译的跨平台应用程序,我必须使用一堆预处理器清楚地对环境进行分类,以避免数据溢出。对错

不完全正确。实际上,往往是真的。

如果您的代码符合标准C ++的领域,那么有一些技术可以避免这样做(就像我上面提到的那样,能够避免依赖于无符号类型的大小)。

如果您的代码使用或提供了标准C ++之外的函数(例如Windows API,不符合C ++标准的posix函数),那么它通常是必要的。即使在这些情况下,也可以避免这种情况。例如,将使用Windows API的函数的版本放在与使用posix的版本不同的源中。并配置构建过程(makefile等) - 例如,如果构建用于windows,则不要在unix版本中编译或链接。