unsigned int vs. size_t

时间:2008-09-25 07:00:04

标签: c++ c size-t

我注意到现代C和C ++代码似乎几乎无处不在地使用size_t而不是int / unsigned int - 从C字符串函数的参数到STL。我很好奇这个原因及其带来的好处。

8 个答案:

答案 0 :(得分:365)

size_t类型是无符号整数类型,它是sizeof运算符(和offsetof运算符)的结果,因此保证它足够大以包含大小系统可以处理的最大对象(例如,8Gb的静态数组)。

size_t类型可能大于,等于或小于unsigned int,并且您的编译器可能会对其进行假设以进行优化。

您可以在C99标准中找到更准确的信息,第7.17节,其草案可在因特网上以pdf格式或在C11标准第7.19节中获得,也可作为{{3 }}

答案 1 :(得分:92)

经典C(Brian Kernighan和Dennis Ritchie在C编程语言中描述的C的早期方言,Prentice-Hall,1978)没有提供size_t。 C标准委员会介绍size_t以消除可移植性问题

Explained in detail at embedded.com (with a very good example)

答案 2 :(得分:68)

简而言之,size_t永远不会消极,并且它会最大化性能,因为它的typedef将是无符号整数类型,足够大 - 但不是太大 - 来表示最大可能对象的大小在目标平台上。

大小永远不应该是负数,实际上size_t是无符号类型。此外,由于size_t是无符号的,因此您可以存储大约是相应签名类型的两倍的数字,因为我们可以使用符号位来表示幅度,就像无符号整数中的所有其他位一样。当我们再获得一位时,我们将我们可以表示的数字范围乘以大约两倍。

所以,你问,为什么不使用unsigned int?它可能无法容纳足够多的数字。在unsigned int为32位的实现中,它可以表示的最大数字是4294967295。某些处理器(如IP16L32)可以复制大于4294967295字节的对象。

所以,你问,为什么不使用unsigned long int?它确实在一些平台上造成了性能损失。标准C要求long占用至少32位。 IP16L32平台将每个32位长实现为一对16位字。这些平台上的几乎所有32位运算符都需要两条指令(如果不是更多),因为它们与两个16位块中的32位一起使用。例如,移动32位长通常需要两条机器指令 - 一条用于移动每个16位块。

使用size_t可以避免这种性能损失。根据{{​​3}},“类型size_t是一个typedef,它是某些无符号整数类型的别名,通常为unsigned intunsigned long,但可能只有unsigned long long。标准C实现应该选择足够大的无符号整数 - 但不要大于需要 - 来表示目标平台上最大可能对象的大小。“

答案 3 :(得分:48)

size_t类型是sizeof运算符返回的类型。它是一个无符号整数,能够表示主机上支持的任何内存范围的字节大小。它(通常)与ptrdiff_t有关,因为ptrdiff_t是有符号整数值,因此sizeof(ptrdiff_t)和sizeof(size_t)相等。

编写C代码时,每当处理内存范围时,总是使用size_t。

另一方面,int类型基本上定义为主机可用于最有效地执行整数运算的(带符号)整数值的大小。例如,在许多旧的PC类型计算机上,值sizeof(size_t)将是4(字节)但sizeof(int)将是2(字节)。尽管CPU可以处理最多4 GiB的(逻辑)存储空间,但16位算术比32位算术快。

只有在关心效率时才使用int类型,因为它的实际精度很大程度上取决于编译器选项和机器架构。特别是C标准指定了以下不变量:sizeof(char)< = sizeof(short)< = sizeof(int)< = sizeof(long)对程序员可用的精度的实际表示没有其他限制对于每种原始类型。

注意:这与Java中的不同(实际上为每个类型'char','byte','short','int'和'long'指定了位精度。)

答案 4 :(得分:23)

类型size_t必须足够大,以存储任何可能对象的大小。无符号整数不必满足该条件。

例如在64位系统中int和unsigned int可能是32位宽,但size_t必须足够大以存储大于4G的数字

答案 5 :(得分:3)

在研究该主题时,glibc手册0.02的摘录也可能是相关的:

版本2.4之前的size_t类型和GCC版本可能存在问题。 ANSI C要求size_t始终是无符号类型。为了与现有系统的头文件兼容,GCC定义了stddef.h' to be whatever type the system's sys / types.h中的size_t定义它。大多数在`sys / types.h'中定义size_t的Unix系统将其定义为有符号类型。库中的某些代码依赖于size_t是无符号类型,如果签名则无法正常工作。

期望size_t无符号的GNU C库代码是正确的。 size_t作为签名类型的定义不正确。我们计划在版本2.4中,GCC将始终将size_t定义为无符号类型,并将fixincludes' script will massage the system's sys / types.h'定义为不与此冲突。

与此同时,我们通过在编译GNU C库时明确告诉GCC使用size_t的无符号类型来解决这个问题。 `configure'将自动检测GCC用于size_t的类型,以便在必要时覆盖它。

答案 6 :(得分:1)

如果我的编译器设置为32位,CREATE PROCEDURE automated AS BEGIN Declare @startDate1 DateTime; Declare @endDate1 DateTime; Declare @month int; set @endDate1=GETDATE(); set @month= DATEPART(mm,Getdate()); if(@month=1 or @month=2 or @month=3) begin set @startDate1= '01/01/' + CONVERT(VARCHAR(4), DATEPART(yy, getUTCDate())) --'01/01/2016' set @endDate1='03/31/'+ CONVERT(VARCHAR(4), DATEPART(yy, getUTCDate())) end else if (@month=4 or @month=5 or @month=6) begin set @startDate1='04/01/'+ CONVERT(VARCHAR(4), DATEPART(yy, getUTCDate())) set @endDate1='06/30/'+ CONVERT(VARCHAR(4), DATEPART(yy, getUTCDate())) end else if (@month=7 or @month=8 or @month=9) begin set @startDate1='07/01/' + CONVERT(VARCHAR(4), DATEPART(yy, getUTCDate())) set @endDate1='09/30/'+ CONVERT(VARCHAR(4), DATEPART(yy, getUTCDate())) end else if (@month=10 or @month=11 or @month=12) begin set @startDate1='10/01/'+ CONVERT(VARCHAR(4), DATEPART(yy, getUTCDate())) set @endDate1='12/31/'+ CONVERT(VARCHAR(4), DATEPART(yy, getUTCDate())) end EXEC Poin.[dbo].[spCalculateSomething] @startDate = @startDate1, @endDate = @endDate1 END 只不过是size_t的typedef。如果我的编译器设置为64位,unsigned int只不过是size_t的typedef。

答案 7 :(得分:-3)

size_t是指针的大小。

因此,在32位或公共ILP32(整数,长,指针)模型中,size_t为32位。 在64位或公共LP64(长,指针)模型中,size_t为64位(整数仍为32位)。

还有其他模型,但这些是g ++使用的模型(至少默认情况下)