我注意到现代C和C ++代码似乎几乎无处不在地使用size_t而不是int / unsigned int - 从C字符串函数的参数到STL。 我很好奇这个原因及其带来的好处。
size_t类型是无符号整数类型,它是sizeof运算符(和offsetof运算符)的结果,因此保证它足够大以包含系统可以处理的最大对象的大小(例如,8Gb的静态数组)。
size_t类型可能大于,等于或小于unsigned int,您的编译器可能会对其进行假设以进行优化。
您可以在C99标准中找到更准确的信息,第7.17节,其草案可在因特网上以pdf格式或在C11标准第7.19节中获得,也可作为pdf草案获得。
-
不。想想使用大型(非巨大)内存模型的x86-16:指针远(32位),但单个对象限制为64k(因此size_t可以是16位)。
-
"最大对象的大小"措辞并不差,但绝对正确。对象的六个可以比地址空间更受限制。
-
"你的编译器可能会假设它":我希望编译器知道size_t可以代表的确切值范围!如果没有,谁呢?
-
@Marc:我认为关键在于编译器可以用这些知识做些什么。
-
我只是希望这种越来越流行的类型不需要包含头文件。
-
实际上,编译器通常在不使用size_t时进行更好的优化,因为无符号类型的定义更严格,因此(在某些情况下)必须检查溢出等。与其他无符号类型相比,指针/数组索引等简单操作可能仍然更快,因为编译器可能不必首先转换为64位整数(如果您的CPU仅执行64位指针运算)。
-
最重要的是,即使在64位上,地址空间也很少超过48位,因此除非需要访问超过2 * sizeof(T) GB的元素,否则我强烈建议将数组大小和索引存储为int而不是< x0>每当你能逃脱它。可以为您节省高达50%的内存,甚至可以加快您的代码速度。
经典C(Brian Kernighan和Dennis Ritchie在C编程语言中描述的C的早期方言,Prentice-Hall,1978)没有提供size_t。 C标准委员会介绍了size_t以消除可移植性问题
在embedded.com上详细解释(有一个很好的例子)
-
另一篇解释size_t和ptrdiff_t的精彩文章:viva64.com/en/a/0050
简而言之,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可以避免这种性能损失。根据这篇精彩的文章,"Type size_t是一个typedef,它是某些无符号整数类型的别名,通常是unsigned int或unsigned long,但可能甚至unsigned long long。每个标准C实现都应该选择无符号整数这足够大 - 但不比需要大 - 表示目标平台上最大可能对象的大小。"
-
很抱歉在这么久之后对此发表评论,但我只需要确认一个unsigned int可以容纳的最大数字 - 也许我误解了你的术语,但我认为无符号int可以容纳的最大数字是4294967295,65356是无符号短线的最大值。
-
如果你的unsigned int占32位,那么是,它可以容纳的最大数字是2 ^ 32 - 1,即4294967295(0xffffffff)。你还有其他问题要问吗?
-
没有其他问题,我只是好奇为什么你使用65,356这意味着16位无符号int,我从来不知道这是最常见的情况。
-
@Mitch:unsigned int中可以表示的最大值可以并且确实因系统而异。它必须至少65536,但它通常4294967295并且在某些系统上可能18446744073709551615(2 ** 64-1)。
-
哦好的。是否有标准或某些东西要求它至少为65536?另外,我刚刚意识到我写的是65356而不是65536 - 哎呀!
-
在本文中,有人说:使用unsigned int作为参数类型,如:void * memcpy(void * s1,void const * s2,unsigned int n);在任何可以表示最大数据对象大小的unsigned int平台上都可以使用。那么我们可以说size_t = unsigned int。我们可以说它们之间没有区别吗? (我的电脑是32位)
-
16位无符号int可以包含的最大值是65535,而不是65536. 65536处的小但重要的差异与16位无符号int中的0相同。
-
C标准(C ++标准说同样的事情)规定无符号int必须能够保存至少65,536个不同值的"标准或某物"。
-
@ gnasher729:你确定C ++标准吗?经过一段时间的搜索,我认为他们只是删除了有关整数范围的所有绝对保证(不包括unsigned char)。标准似乎在任何地方都不包含字符串'65535'或'65536',并且'+32767'仅在注释中出现(1.9:9)作为可能在int中表示的最大整数;即使INT_MAX不能小于此值,也不能保证!
-
@MarcvanLeeuwen在18.3.3 / 2中,C ++ 11标准说:"内容与标准C库头相同"。我认为对内容的要求是相同的。 C99在5.2.4.2.1 / 1中说"它们的实现定义值的大小(绝对值)应与所示的值相等或更大,具有相同的符号。",后跟值本身。
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'指定了位精度)。
-
int的事实上的定义是它在16台机器上是16位,在更大的机器上是32位。已经编写了太多的代码,假设int是32位宽,现在要改变它,因此人们应该总是使用size_t或{,u} int {8,16,32,64} _t如果他们想要特定的东西 - - 作为预防措施,人们应该始终使用这些,而不是整数整数类型。
-
"它是一个无符号整数,能够表示主机支持的任何内存范围的字节大小。" - >否。size_t能够表示任何单个对象的大小(例如:数字,数组,结构)。整个存储器范围可能超过size_t
类型size_t必须足够大,以存储任何可能对象的大小。 Unsigned int不必满足该条件。
例如,在64位系统中int和unsigned int可能是32位宽,但size_t必须足够大以存储大于4G的数字
-
"object"是标准使用的语言。
-
我认为如果编译器可以接受类型X使得sizeof(X)产生大于4G的值,那么size_t只需要那么大。大多数编译器会拒绝,例如typedef unsigned char foo[1000000000000LL][1000000000000LL],如果超过文档化的实现定义限制,甚至可以合法地拒绝foo[65536][65536];。
-
@MattJoiner:措辞很好。"对象"根本不含糊,而是定义为"存储区域"。
在研究该主题时,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使用unsigned类型的size_t来解决这个问题。 `configure'将自动检测GCC用于size_t的类型,以便在必要时覆盖它。
如果我的编译器设置为32位,size_t只不过是unsigned int的typedef。如果我的编译器设置为64位,size_t只不过是unsigned long long的typedef。
-
对于某些操作系统上的两种情况,可以将其定义为unsigned long。
size_t是指针的大小。
因此,在32位或公共ILP32(整数,长,指针)模型中,size_t是32位。
并且在64位或公共LP64(长,指针)模型中,size_t是64位(整数仍然是32位)。
还有其他模型,但这些是g ++使用的模型(至少默认情况下)
-
size_t不一定与指针大小相同,但通常是。指针必须能够指向内存中的任何位置; size_t只需要足够大以表示最大单个对象的大小。