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

时间:2015-08-19 08:44:03

标签: c language-lawyer c89

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

首先,answer表明long确实不能保证size_t足够大。另一方面,我看到此answer建议在C99之前使用printf("%lu", (unsigned long)x)xsize_t

所以问题是你可以假设,或者你保证long足以在预C99 中保留size_t。另一个问题是,是否存在size_t适合任何其他标准化整数类型的保证(除ssize_tptrdiff_t等明显例外情况外。

2 个答案:

答案 0 :(得分:7)

没有这样的保证。

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

另请注意,实施SIZE_MAX的最小值为65535,而ULONG_MAX的最小值为42949672952147483647 LONG_MAX }})。 (请注意,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没有扩展整数类型)。

答案 1 :(得分:1)

  

所以问题是你可以假设,或者你保证long足以在预C99 中保留size_t

不是long,而是unsigned long

在C89 / C90中,size_t必须是无符号整数类型。 C89 / C90中恰好有4个无符号整数类型unsigned charunsigned shortunsigned intunsigned long。因此, / 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正式采用的。严格来说,#C; ANSI C"应该参考ISO C11 - 但由于历史原因这个短语仍被用来指1989年的标准。)