2017-04-14 131 views
1

我在Windows上做C++开发与Visual Studio编译器,专门的Visual Studio 2015年更新3C++之间的差异无符号整型和unsigned long int类型

对于我使用unsigned int类型/无符号的一些DSP相关工作长数据类型。我想知道这两种内置C/C++类型有什么区别。

我通过Google和SO搜索了一下,发现了这些引用。

  1. Types documentation上cppreference.com
  2. Types documentation MSDN上的Visual Studio 2015年
  3. Types documentation的GNU C/C++(如G++ compiler指出,C/C++使用相同的默认类型的实现,我指到C DOC这里)

我假定cppreference文档是ISO C++ 11标准的总结。因此,从 “标准” 无符号unsigned int类型是依赖于LP/ILP 32/64数据模型16/32位,而unsigned long类型unsigned long int类型是依赖于LP 32/64比特/ 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. 如果我有一个应用程序的Windows系统在Visual Studio编译的有关工作,basicall 无符号 == unsigned long类型。对或错?
  3. 如果我有工作在Linux/Windows的由GNU编译器编译应用程序我必须确保是否unsigned long类型 == unsigned int类型unsigned long类型 == 无符号长长,以避免数据溢出。对或错
  4. 如果我有一个跨平台的应用程序,可能是由所有这些Visual Studio/GNU/Clang/Intel编译器编译的,我必须用一堆预处理器清楚地分类环境,以避免数据溢出。对或错

在此先感谢。

编辑: 感谢@PeterRuderman指出超出ceil值为无符号类型不是未定义的行为。

然后我的问题1将变更为:

  1. 对于无符号长64位,将超出上限4,294,967,295使得其自身环绕?
+0

请注意,即使'unsigned int'和'unsigned long'碰巧具有相同的范围和表示形式,它们仍然是不同的类型。 –

回答

1

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

还要注意溢出一个unsigned整数不是未定义的行为。定义的行为是价值环绕。 (例如std::numeric_limits<uint64_t>::max() + 43 == 42)。对于签名的类型,这是不正确的,其中溢出是未定义的行为。

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

+0

很确定的签名溢出是实现定义的而不是直接的未定义行为。也许不是** [expr] **注4似乎仍然称它为未定义的N4594 – user4581301

+0

感谢您的快速回答。还有一个问题与此有关。当我们在库中拥有所有这些良好的数据类型时,为什么仍然需要short,int,long和它们的无符号对应类型?或者从另一个角度来看,为什么short,int,long和它们的无符号对应实现不遵循与中类型相同的规则? – yc2986

+2

cstdint中的类型*相对*新。委员会无法在不破坏大量代码的情况下删除旧的类型。而且,出于性能方面的考虑,让编译器选择整数大小会更好。 –

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以外的整数值(可支持更大范围的类型)将被转换,因此它在该范围内(在数学上相当于重复添加或减去4294967296 [注意最后一位数字])。换句话说,它将“环绕”。

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

假设Visual Studio 2015是正确的,正如您链接到的文档所述。未来的微软产品可能会也可能不会这样 - 这是一个实施决定。

如果我有GNU编译器在Linux/Windows的工作,我必须确保无符号长== unsigned int类型或unsigned long类型==无符号长长是否以避免数据溢出编译的应用程序。对或错

其实是错误的。

只有在您移植依赖这些假设为真的代码时才是如此。

您可以使用的技术,以便您的代码不依赖于这些假设是真实的。例如,您可以安全地检测涉及两个unsigned值的操作何时溢出或下溢,并采取措施产生所需的结果。如果所有操作都被正确检查,您可以避免依赖特定尺寸的类型。

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

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

如果你的代码坚持标准C++的领域,有技术可以避免这样做(就像我上面提到的,避免依赖于无符号类型的大小)。

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

+0

感谢您的详细解答@Peter。我认为'unsigned short int'有点适用于范围从0-65535的16位数据类型。只是混淆了为什么'unsigned short','unsigned int','unsigned long'和'unsigned long long'之间存在重叠。 – yc2986

+0

重叠是历史性的,并且从C中继承而来。“short”类型('signed'和'unsigned')是平台支持的“小”类型,用于节省内存。 “长”类型是一个平台可以支持的长类型。 “int”类型是“本地”类型(例如用硬件实现寄存器和对它们的操作),实际上在某些机器上相当于“短”,而在其他机器上相当于“长”。后来,本地更多的硬件支持32位类型,所以'int'和'long'等价变得更为常见。然后,硬件支持64位,并且“long long”类型诞生了。 – Peter

+0

它比这更复杂一些(例如,有机器和编译器,它们用于整数类型的奇数位)。但是,就16到32到64位而言,类型的原因是它们之间的重叠。 – Peter

相关问题