作为一般命题,使用size_t
andptrdiff_t
比使用简单的unsigned int
and更受欢迎int
。 size_t
并且ptrdiff_t
几乎是编写健壮且可广泛移植的程序的唯一方法。
然而:没有免费的午餐。正确使用size_t
也需要一些工作——只是,如果你知道你在做什么,它比试图在不使用size_t
.
此外,size_t
还有无法使用%d
or打印的问题%u
。理想情况下,您想使用%zu
,但不幸的是,并非所有实现都支持它。
如果您有一个不使用的大型且编写不佳的程序,那么size_t
它可能充满了错误。其中一些错误将被掩盖或解决。如果您尝试将其更改为 use size_t
,则该程序的某些解决方法将失败,可能会发现曾经隐藏的错误。最终你会解决这些问题并实现你想要的更强大、更可靠和更便携的程序,但这个过程将是一个艰难的过程。我怀疑这就是作者所说的“很可能由于这种替换,会出现新的错误”。
将程序更改为使用size_t
有点像尝试const
在所有正确的地方添加。你做了你认为需要做的改变,然后重新编译,你得到一堆错误和警告,你修复这些并重新编译,你得到一堆更多的错误和警告,等等。这至少是一个麻烦,而且有时需要大量的工作。但如果您想让代码更加健壮和可移植,这通常是唯一的方法。
问题的很大一部分是让编译器满意。它会警告一堆东西,你通常会想要修复它抱怨的所有东西,即使它抱怨的一些东西是棘手的,不太可能引起问题。但是说“是的,我可以忽略这个特别的警告”是很危险的,所以最后,正如我所说,你通常会想要解决所有问题。
作者最抢眼的说法是
程序所需的内存大小也将大大增加。
我怀疑这是夸大其词——在大多数情况下,我怀疑内存会“大大”增加——但它可能至少会增加一点点。问题是在 64 位系统上,size_t
并且ptrdiff_t
很可能是 64 位类型。如果出于某种原因你有这些的大型数组,或者包含这些的大型结构数组,并且如果你以前使用过一些 32 位类型(可能是普通的int
或unsigned int
),是的,你会看到内存增加。
然后你会想问,我真的需要能够描述 64 位大小吗? 64 位编程为您提供了两件事:(a) 能够寻址超过 4Gb 的内存,以及 (b) 能够拥有大于 4Gb 的单个对象。如果您希望总数据使用量大于 4Gb,但您不需要单个对象大于 4Gb,并且如果您不想一次从文件中读取超过 4Gb 的数据(使用单read
或fread
调用,即),您实际上并不需要到处都是 64 位大小的变量。
因此,为了避免臃肿,您可能会做出明智的选择,例如,unsigned int
(甚至unsigned short
)而不是size_t
在某些地方使用。作为一个简单的例子,如果你有
size_t x = sizeof(int);
printf("%zu\n", x);
你可以把它改成
unsigned int x = sizeof(int);
printf("%u\n", x);
没有任何可移植性损失,因为我可以非常自信地保证您的代码永远不会在具有 34359738368 位int
的机器上运行(或者至少在我们的有生之年:-) )。
但是最后一个例子,尽管它是微不足道的,但也说明了其他容易侵入的问题。类似的代码
unsigned int x = sizeof(y);
printf("%u\n", x);
显然不是很安全,因为无论如何y
,它都有可能太大以至于它的大小不适合无符号整数。因此,如果您或您的编译器真的关心类型正确性,那么在分配size_t
给unsigned int
. 要关闭这些警告,您可能需要显式强制转换,如
unsigned int x = (unsigned int)sizeof(int);
可以说,这个演员阵容非常合适。编译器的运行假设是任何对象都可能非常大,任何将 asize_t
插入 a 的尝试都unsigned int
可能会丢失数据。演员说你已经考虑过这个案子:你说,“是的,我知道,但在这种情况下,我知道它不会溢出,所以请不要再警告我这个案子了,但是请务必警告我任何其他人,这可能不那么安全。”
PS我被否决了,所以如果我给了错误的印象,让我明确一点(正如我在开篇所说的那样)size_t
并且ptrdiff_t
非常受欢迎。一般来说,有充分的理由使用它们,没有充分的理由不使用它们。(说到这里,卡尔波夫也不是说不使用它们——只是强调了一些可能会出现的问题。)