在ANSI C(C89)中如何使用printf打印size_t和ptrdiff_t?

6

我知道这个问题在SO上已经被问了很多次,但我的问题特定于ANSI C(C89)。

在C99中,有子规范器zt,但在ANSI C中不支持。

那么使用p规范器呢?


4
据我所知, ANSI 自动采用 ISO 标准,因此您应该能够使用相同的标准。如果您指的是 C89/90(这是明确的),则无法更改。请注意,C99 不是标准 C;它应该是 C11。 - too honest for this site
5
@levengli:请不要说这种无稽之谈!size_t不能是int,而且在一些8/16位和大多数64位架构中,ptrdiff_t也不会是int - too honest for this site
3
@Olaf,争论这个有什么意义呢?OP明确要求关于C89的问题。OP对他的环境了解得比你多,所以如果他问关于C89的问题,就简单地回答或不回答即可。 - nos
3
您可以使用 lu 将其打印出来,将值强制转换为 (unsigned long) - 实际值可能按照某个大的模数显示,但这大概是在如此过时的标准下所能获得的最好效果了。 - Antti Haapala -- Слава Україні
5
@Olaf:确实,2011年ISO C标准是美国国家标准协会(ANSI)目前承认的标准。但你应该知道,实际上几乎没有人把C11称为“ANSI C”。即使没有解释性的“(C89)”,也很清楚OP是在问C89/C90。OP的错误在于称那种语言为“ANSI C”。如果你想指出这一点,那很好,但假装OP真的想问一个较新的标准并不有用。 - Keith Thompson
显示剩余27条评论
1个回答

14

size_t是一个由实现定义的无符号整数类型。 ptrdiff_t是一个由实现定义的有符号整数类型。

在C89/C90(通常但严格来说不正确地称为“ANSI C”)中,没有这些类型的特殊格式说明符。但最宽的整数类型是long intunsigned long int,它们当然有自己的格式说明符。

要打印size_t值,请将其转换为unsigned long并使用"%lu"

要打印ptrdiff_t值,请将其转换为long并使用"%ld"

请注意,如果您的代码随后使用C99或C11编译器进行编译,则size_t和/或ptrdiff_t可能比long宽,代码可能会失败。(据我所知,64位Windows接口具有32位long,因此在实践中可能存在问题。)

在C99及更高版本中,只需使用%zu表示size_t%td表示ptrdiff_t即可。如果您希望您的代码真正具有可移植性,请考虑使用#if测试__STDC_VERSION__的值。

如果你使用的编译器只部分符合C99或C11标准,可能会遇到问题。你可能会有一个不完全支持C99但提供了long long的编译器。但是对于打印size_t值来说,这只有在要打印的值实际超过ULONG_MAX(至少为2^32-1)时才会成为问题。对于ptrdiff_t值,只要不超过LONG_MAX(至少为2^31-1),转换为long就可以。最后,如果你知道要打印的值不会太大,你可以将其强制转换为int并使用%d。我建议将其转换为unsigned long或long,但用int也可以。关于使用p说明符呢?不行,%p仅适用于void*指针类型,而且输出格式是实现定义的(通常是十六进制,但我见过其他表示方法)。

1
C89规定:“有四种带符号整型,分别为signed char、short int、int和long int”。这条规定的问题在于,几乎没有任何现有的主要实现都完全按照它来执行。size_t可能被定义为long long unsigned int或者__uint64等等。你该找谁? - n. m.
1
@n.m.: 支持 long long unsigned int 并且对其任何使用不发出警告信息的编译器不符合 C89/C90 标准。在 C89/C90 中,long long unsigned int 是语法错误。 - Keith Thompson
支持long long unsigned int的编译器,如果在使用它时没有发出至少一个警告消息,则不符合C89/C90编译器的规范。除非我错过了什么,否则在包括(当前)标准在内之前,从未要求警告关于传递给printf的错误可变参数等问题。 - too honest for this site
3
@BiteBytes: %p 要求一个 void* 类型的参数。指针不是整数,它们不能安全地互换使用。如果使用任何类型的参数而不是 void* 来使用 %p,将会有未定义的行为。 (也许可以使用 char*unsigned char*signed char* 作为 %p 的参数,但无论如何我都会将它们强制转换为 void*。) - Keith Thompson
1
@n.m.:我宁愿将 size_t 强制转换为 unsigned long 并使用 %u 进行打印。只要被打印的值不超过 2^32-1,就可以保证打印出正确的结果。 - Keith Thompson
显示剩余11条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接