提问



我在C中size_t感到困惑。我知道它是由sizeof运算符返回的。但究竟是什么呢?它是数据类型吗?


我们说我有一个for循环:


for(i = 0; i < some_size; i++)


我应该使用int i;还是size_t i;?

最佳参考


来自维基百科:[68]



??根据1999年ISO C标准
??(C99),size_t是无符号整数
??类型至少为16位(参见章节
??7.17和7.18.3)。

??
??size_t是无符号数据类型
??由几个C/C ++标准定义,
??例如C99 ISO/IEC 9899标准,
??在stddef.h中定义.1它可以
??通过包含进一步导入
??stdlib.h作为此文件内部子
??包括stddef.h[69]

??
??此类型用于表示
??对象的大小。图书馆功能
??采取或返回大小期望他们
??是类型或具有返回类型
??的size_t。而且,最多
??经常使用的基于编译器
??运算符sizeof应该评估为a
??与...兼容的常数值
??size_t



作为一个含义,size_t是一种保证保存任何数组索引的类型。

其它参考1


size_t是无符号类型。因此,它不能表示任何负值(< 0)。你在计算某些东西时使用它,并确保它不会是负面的。例如,strlen()返回size_t,因为字符串的长度必须至少为0. [70]


在您的示例中,如果循环索引始终大于0,则使用size_t或任何其他无符号数据类型可能是有意义的。


当您使用size_t对象时,您必须确保在使用它的所有上下文中,包括算术,您需要非负值。例如,让我们说你有:


size_t s1 = strlen(str1);
size_t s2 = strlen(str2);


你想找到str2str1长度的差异。你做不到:


int diff = s2 - s1; /* bad */


这是因为分配给diff的值总是为正数,即使s2 < s1也是如此,因为计算是使用无符号类型完成的。在这种情况下,根据您的用例,最好使用int(或long long)s1s2


C/POSIX中有一些功能可以/应该使用size_t,但不要因为历史原因。例如,fgets的第二个参数理想情况下应该是size_t,但是是int

其它参考2


size_t是一种可以保存任何数组索引的类型。


根据实施情况,它可以是以下任何一种:


unsigned char


unsigned short


unsigned int


unsigned long


unsigned long long


这是我的机器stddef.h中定义size_t的方式:


typedef unsigned long size_t;

其它参考3


如果您是经验型


echo | gcc -E -xc -include 'stddef.h' - | grep size_t


Ubuntu 14.04 64位GCC 4.8的输出:


typedef long unsigned int size_t;


注意,stddef.h由GCC提供,而不是在GCC 4.2中src/gcc/ginclude/stddef.h下的glibc。


有趣的C99外观



  • mallocsize_t作为参数,因此它确定了可以分配的最大大小。


    由于sizeof也返回它,我认为它限制了任何数组的最大大小。


    另请参见:C 中数组的最大大小


其它参考4


types.h的联机帮助页说:[72]



??size_t应为无符号整数类型


其它参考5


由于没有人提及它,size_t的主要语言意义是sizeof运算符返回该类型的值。同样,ptrdiff_t的主要意义是从另一个指针中减去一个指针将产生该类型的值。接受它的库函数这样做是因为它允许这些函数在可能存在这些对象的系统上使用大小超过UINT_MAX的对象,而不会强迫调用者浪费代码在较大类型的系统上传递大于unsigned int的值对所有可能的对象都足够了。

其它参考6


size_tint不可互换。例如,在64位Linux上size_t的大小为64位(即sizeof(void*)),但int为32位。


另请注意,size_t未签名。如果你需要签名版本,那么在某些平台上有ssize_t,它与你的例子更相关。


作为一般规则,我建议对大多数一般情况使用int,并且只在特定需要时使用size_t/ssize_t(例如mmap())。

其它参考7


通常,如果从0开始向上,则始终使用无符号类型以避免溢出将您带入负值情况。这非常重要,因为如果您的数组边界恰好小于循环的最大值,但是您的循环最大值恰好大于您的类型的最大值,那么您将回绕负数并且可能会遇到分段错误(SIGSEGV) )。所以,一般来说,永远不要使用int作为从0开始向上的循环。使用未签名。[73]

其它参考8


size_t是无符号整数数据类型。在使用GNU C库的系统上,这将是unsigned int或unsigned long int。 size_t通常用于数组索引和循环计数。

其它参考9


size_t 或任何无符号类型可能被视为循环变量,因为循环变量通常大于或等于0。


当我们使用 size_t 对象时,我们必须确保在使用它的所有上下文中,包括算术,我们只需要非负值。例如,以下程序肯定会给出意想不到的结果:


// C program to demonstrate that size_t or
// any unsigned int type should be used 
// carefully when used in a loop

#include
int main()
{
const size_t N = 10;
int a[N];

// This is fine
for (size_t n = 0; n < N; ++n)
a[n] = n;

// But reverse cycles are tricky for unsigned 
// types as can lead to infinite loop
for (size_t n = N-1; n >= 0; --n)
printf("%d ", a[n]);
}

Output
Infinite loop and then segmentation fault

其它参考10


根据我的理解,size_t是一个unsigned整数,其位大小足以容纳本机架构的指针。


所以:


sizeof(size_t) >= sizeof(void*)