我正在使用Visual Studio Compiler在Windows上进行C ++开发,特别是Visual Studio 2015 Update 3。
对于某些与DSP相关的工作,我使用 unsigned int / unsigned long 数据类型。我想知道这两个内置的C / C ++类型有什么区别。
我通过Google和SO搜索了一下,发现了这些参考资料。
我认为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相同。
所以我的问题如下:
提前致谢。
修改 感谢@PeterRuderman指出超出无符号类型的ceil值并不是未定义的行为。
然后我的问题1将改为:
答案 0 :(得分:2)
简短的回答是,sizeof(unsigned)
不能保证等于sizeof(unsigned long)
,但确实恰好在MSVC中。如果您需要以独立于平台的方式确定整数的大小,请使用<cstdint>
:uint32_t
和uint64_t
中的类型。在可移植代码中避免使用long
,这会导致很多麻烦。
另请注意,溢出 unsigned 整数不是未定义的行为。定义的行为是值环绕。 (例如std::numeric_limits< uint64_t >::max() + 43 == 42
)。对于签名的类型,情况并非如此,其中溢出是未定义的行为。
要回答最后一个问题,64位整数可以存储[0,2 64 - 1]范围内的值。 2 32 + 1不会导致环绕。
答案 1 :(得分:1)
在C ++标准中,unsigned int
仅保证能够表示从0
到65535
的值。实际上,这相当于16位。实现(即编译器)可以为unsigned int
提供更大的范围,但不是必需的。
相比之下,unsigned long int
可以保证能够代表0
到4294967295
范围内的值。实际上,这相当于32位。同样,实现可能支持更大的范围。
这些类型的范围和大小是实现定义的。实施必须满足最低要求,并选择其选择的文件。
实现提供32位的unsigned int
和unsigned long int
并不罕见。或者,一个或两个是64位。如您所述,Visual Studio 2015的文档指出unsigned int
和unsigned long int
都代表0
到4294967295
的值。
对于像g ++这样可以针对一系列系统的编译器,选择通常由目标系统决定。因此,对于32位系统,g ++的构建可能支持unsigned long
的不同范围,而不是64位系统的构建。
回答你的问题
对于无符号长64位,超出上限4,294,967,295的未定义行为或正确行为?
虽然它可能无法产生您期望的结果,但它具有良好定义的行为。 C ++中的无符号整数类型使用模运算。将转换超出0
到4294967295
范围的整数值(可支持更大范围的类型),使其在该范围内(数学上等效于重复加或减{{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版本中编译或链接。