`long`保证与`size_t`一样宽

当寻找unsigned long证据足以容纳size_t以便成为printf参数时,我遇到了两个事实(oid)s。

首先,这个答案表明long确实不足以保证size_t足够大。 另一方面,我看到这个答案建议在前C99中使用printf("%lu", (unsigned long)x)xsize_t

所以问题是你可以假设或者你保证在C99之前持有size_t long足够long 。 另一个问题是,是否有任何保证size_t适合任何其他标准化整数类型(除了明显的例外,如ssize_tptrdiff_t等)。

没有这样的保证。

虽然实现对于longsize_t具有相同的大小是常见的,但情况并非总是如此。 正如评论中所提到的,Windows 64位对于longsize_t具有不同的大小。

另请注意,实现的SIZE_MAX的最小值为65535ULONG_MAX的最小值为4294967295LONG_MAX2147483647 )。 (注意, SIZE_MAX出现在C99中。)这意味着size_t保证至少为16位,但unsigned long / long保证至少为32位。

编辑:问题在这个答案之后发生了一些变化……所以:

所以问题是你可以假设或者你保证在C99之前持有size_t的时间足够长。

即使在C89中也没有这样的保证。 long可以是32位, size_t 64位。 (请参阅上面Windows 64位中带有MSVC的C89示例。)

另一个问题是,是否有任何保证size_t适合任何其他标准化整数类型(除了明显的例外,如ssize_t,ptrdiff_t等)。

标准也没有这样的保证。 size_t是另一个标准无符号整数类型的别名(它不能是扩展整数类型,因为C89没有扩展整数类型)。

所以问题是你可以假设或者你保证在C99之前持有size_t long足够long

long ,但unsigned long

在C89 / C90中, size_t必须是无符号整数类型。 C89 / C90中正好有4个无符号整数类型unsigned charunsigned shortunsigned intunsigned long 。 因此, 在C89 / C90中size_t可以不宽于unsigned long ,因此任何类型size_t值都可以转换为unsigned long而不会丢失信息。 (这仅适用于unsigned long ,而不适用于long 。)

这种隐式保证在C99中消失了,引入了unsigned long long扩展整数类型 。 在C99及更高版本中, size_t可以比unsigned long更宽。 例如,C99实现可能具有32位long和64位long long ,并且使size_t成为unsigned long long的别名。

即使在C89 / C90中,只有在符合C89 / C90标准的情况下才能依靠保证。 前C99编译器通常在C89 / C90标准之上提供扩展 – 例如编译器可能支持long long ,并且可能使size_t成为unsigned long long的别名,即使编译器不完全支持C99(或C11)标准。

问题是关于printf 。 请记住, printf的参数必须是格式字符串的适当类型。 这个:

 printf("sizeof (int) = %lu\n", sizeof (int)); 

具有未定义的行为,除非size_t恰好是unsigned long的别名(即使size_tunsigned long碰巧具有相同的大小)。 您需要将值强制转换为正确的类型:

 printf("sizeof (int) = %lu\n", (unsigned long)sizeof (int)); 

对于C99及更高版本,您可以直接打印size_t值:

 printf("sizeof (int) = %zu\n", sizeof (int)); 

如果愿意,您可以测试__STDC_VERSION__的值以确定使用哪一个。

(关于C标准版本的说明。第一个C标准由ANSI于1989年出版。它于1990年由ISO重新发布,增加了额外的样板部分。因此C89和C90是描述相同语言的两个不同文档。后来的C99和C11标准由ISO发布。所有三种ISO C标准均由ANSI正式采用。严格来说,“ANSI C”应参考ISO C11 – 但由于历史原因,该短语仍用于指代1989年标准。)