当寻找unsigned long
足以容纳size_t
以证明printf
参与的证据时,我遇到了两个事实(oid)s。
首先,answer表明long
确实不能保证size_t
足够大。另一方面,我看到此answer建议在C99之前使用printf("%lu", (unsigned long)x)
,x
为size_t
。
所以问题是你可以假设,或者你保证long
足以在预C99 中保留size_t
。另一个问题是,是否存在size_t
适合任何其他标准化整数类型的保证(除ssize_t
,ptrdiff_t
等明显例外情况外。
答案 0 :(得分:7)
没有这样的保证。
虽然long
和size_t
的实现通常具有相同的大小,但情况并非总是如此。如评论中所述,Windows 64位具有long
和size_t
的不同大小。
另请注意,实施SIZE_MAX
的最小值为65535
,而ULONG_MAX
的最小值为4294967295
(2147483647
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 char
,unsigned short
,unsigned int
和unsigned long
。因此,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_t
和unsigned 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年的标准。)