无符号整数与size_t


492

我注意到,现代C和C ++代码似乎在所有地方都使用/ size_t而不是使用-从C字符串函数的参数到STL。我对此的原因及其带来的好处感到好奇。intunsigned int

Answers:


388

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

size_t类型可能比比大,等于,或小于unsigned int,你的编译器可能会做出假设它进行优化。

您可以在C99标准的第7.17节中找到更精确的信息,该草案的草案以pdf格式在Internet上提供,或者在C11标准的第7.19节中也以pdf草案的形式提供


50
不。考虑具有大型(不是大型)内存模型的x86-16:指针很远(32位),但是单个对象限制为64k(因此size_t可以为16位)。
10年

8
“最大物体的大小”不是措辞不佳,而是绝对正确的。一个对象的六进制可能比地址空间要受限制得多。
gnasher729 2014年

3
“您的编译器可能对此做假设”:我希望编译器知道size_t可以表示的值的确切范围!如果没有,谁做?
Marc van Leeuwen 2014年

4
@Marc:我认为更重要的是,编译器可能能够利用这些知识来做某事

8
我只是希望这种越来越流行的类型不需要包含头文件。
user2023370 '16


73

简而言之,size_t它永远不会是负数,并且会最大化性能,因为它的类型定义为无符号整数类型,该类型足够大(但又不太大)以表示目标平台上最大可能对象的大小。

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

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

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

使用size_t可以避免这种性能损失。根据这篇精彩的文章,“ Type size_t是typedef,它是某些无符号整数类型(通常是unsigned intunsigned long,但甚至可能是)的别名unsigned long long。每个Standard C实现都应选择足够大但不超过所需整数的无符号整数-代表目标平台上最大可能物体的大小。”


1
抱歉,这么长时间后才对此发表评论,但我只想确认unsigned int可以容纳的最大数量-也许我误解了您的术语,但我认为unsigned int可以容纳的最大数量是4294967295,其中65356是最大无符号空缺。
米奇2012年

如果您的无符号int占用32位,则可以,它可以容纳的最大数字为2 ^ 32-1,即4294967295(0xffffffff)。你还有其他问题要问吗?
Rose Perrone

3
@Mitch:罐中可以表示的最大值,unsigned int并且确实因一个系统而异。它必须至少为 65536,但是在某些系统上通常429496729518446744073709551615(2 ** 64-1)。
基思·汤普森

1
16位无符号int可以包含的最大值是65535,而不是65536。与65536一样小的但重要的区别与16位无符号int的0相同。
Sie Raybould 2013年

1
@ gnasher729:您确定要使用C ++标准吗?搜索一段时间后,我的印象是,他们只是删除了有关整数范围的所有绝对保证(不包括unsigned char)。该标准似乎在任何地方都不包含字符串'65535'或'65536',并且'+32767'仅出现在注释中(1.9:9),可能是最大的整数,可以用表示int;即使INT_MAX不能小于此值,也无法保证!
Marc van Leeuwen 2014年

51

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中的不同(Java实际上为Java的“ char”,“ byte”,“ short”,“ int”和“ long”类型指定了位精度)。


int的实际定义是在16台计算机上为16位,在任何更大的计算机上为32位。假设int为32位宽,因此编写了太多代码,现在就进行更改,结果,如果人们想要特定的东西,人们应该始终使用size_t或{,u} int {8,16,32,64} _t- -作为预防措施,人们应该始终使用这些而不是整数整数类型。
清晰的2014年

3
“这是一个无符号整数,能够表示主机支持的任何内存范围的大小(以字节为单位)。” -> No. size_t能够表示任何单个对象的大小(例如:数字,数组,结构)。整个存储范围可能会超出size_t
chux-恢复Monica

“在编写C代码时,无论何时处理内存范围,都应始终使用size_t。” -这意味着每个数组的每个索引都应该是size_t-我希望你不是那个意思。大多数时候,我们不处理地址空间和可移植性的基数甚至很重要的数组。在这些情况下,你会采取的size_t。在所有其他情况下,您都将从(带符号的)整数中取出索引。因为未签名的未预料到的下溢行为引起的混乱(不加警告)比其他情况下可能出现的可移植性问题更常见且更糟。
johannes_lalala

23

类型size_t必须足够大以存储任何可能的对象的大小。Unsigned int不必满足该条件。

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


38
“对象”是标准使用的语言。
R .. GitHub停止帮助ICE,2010年

2
我认为size_t,如果编译器可以接受X类型,从而使sizeof(X)产生的值大于4G,那么它就必须大得多。大多数编译器都会拒绝例如typedef unsigned char foo[1000000000000LL][1000000000000LL]foo[65536][65536];如果超出了记录的实现定义的限制,甚至可能会被合法拒绝。
超级猫

1
@MattJoiner:措辞很好。“对象”一点也不模糊,而是定义为“存储区域”。
Lightness Races in Orbit 2015年

4

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

2.4版之前的size_t类型和GCC版本存在潜在问题。ANSI C要求size_t始终为无符号类型。为了与现有系统的头文件兼容,GCC在stddef.h' to be whatever type the system'ssys / 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'ssys / types.h'定义为与此不冲突。

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


2

如果将我的编译器设置为32位,size_t则仅是typedef unsigned int。如果我的编译器设置为64位,size_t则仅是typedef unsigned long long


1
可以unsigned long在某些操作系统上针对两种情况进行定义。
StaceyGirl

-4

size_t是指针的大小。

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

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


15
size_t尽管通常与指针大小不一定相同。指针必须能够指向内存中的任何位置。size_t只需足够大即可代表最大单个对象的大小。
Keith Thompson
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.