寻找有关使用的说明 "zd"
同 printf()
。
当然,以下对于C99及更高版本是正确的。
void print_size(size_t sz) {
printf("%zu\n", sz);
}
C规范 似乎 允许 printf("%zd\n", sz)
取决于如何阅读:
7.21.6.1 fprintf
功能
z
指定以下内容 d
, i
, o
, u
, x
, 要么 X
转换说明符适用于a size_t
或相应的有符号整数类型参数;或者说是以下 n
转换说明符适用于指向对应的有符号整数类型的指针 size_t
论据。 C11dr§7.21.6.17
这应该被解读为
- “
z
指定以下内容 d
...转换说明符适用于a size_t
或相应的有符号整数类型参数......“(两种类型)和”z
指定以下内容 u
...转换说明符适用于a size_t
或相应的有符号整数类型参数......“(两种类型)
要么
- “
z
指定以下内容 d
...转换说明符适用于相应的有符号整数类型参数...“(仅限带符号类型)和”z
指定以下内容 u
...转换说明符适用于a size_t
“(仅限无符号类型)。
我一直在使用#2定义,但现在不太确定。
哪个是正确的,1,2或其他什么?
如果#2是正确的,那么可以使用的类型的示例是什么 "%zd"
?
printf
用一个 "%zd"
format需要一个与unsigned类型对应的signed类型的参数 size_t
。
标准C不提供此类型的名称或确定其类型的好方法。如果 size_t
是一个typedef unsigned long
例如,然后 "%zd"
期望一个类型的参数 long
,但这不是一个可移植的假设。
该标准要求相应的有符号和无符号类型对两种类型中可表示的非负值使用相同的表示。一个脚注说这意味着它们可以作为函数参数互换。所以这:
size_t s = 42;
printf("s = %zd\n", s);
应该工作,并应打印“42”。它将解释价值 42
,无符号类型 size_t
,好像它是相应的签名类型。但是,从那以后真的没有理由这样做 "%zu"
也没有诉诸其他语言规则,也是正确和明确的。和 "%zu"
效劳于 所有 类型的值 size_t
,包括相应签名类型范围之外的那些。
最后,POSIX定义了一个类型 ssize_t
在标题中 <unistd.h>
和 <sys/types.h>
。虽然POSIX没有明确说出来,但据推测 ssize_t
将是对应的签名类型 size_t
。
因此,如果您正在编写特定于POSIX的代码, "%zd"
是(可能)打印类型的正确格式 ssize_t
。
printf
用一个 "%zd"
format需要一个与unsigned类型对应的signed类型的参数 size_t
。
标准C不提供此类型的名称或确定其类型的好方法。如果 size_t
是一个typedef unsigned long
例如,然后 "%zd"
期望一个类型的参数 long
,但这不是一个可移植的假设。
该标准要求相应的有符号和无符号类型对两种类型中可表示的非负值使用相同的表示。一个脚注说这意味着它们可以作为函数参数互换。所以这:
size_t s = 42;
printf("s = %zd\n", s);
应该工作,并应打印“42”。它将解释价值 42
,无符号类型 size_t
,好像它是相应的签名类型。但是,从那以后真的没有理由这样做 "%zu"
也没有诉诸其他语言规则,也是正确和明确的。和 "%zu"
效劳于 所有 类型的值 size_t
,包括相应签名类型范围之外的那些。
最后,POSIX定义了一个类型 ssize_t
在标题中 <unistd.h>
和 <sys/types.h>
。虽然POSIX没有明确说出来,但据推测 ssize_t
将是对应的签名类型 size_t
。
因此,如果您正在编写特定于POSIX的代码, "%zd"
是(可能)打印类型的正确格式 ssize_t
。
根据我所做的小测试,“zd”总是正确的,但“zu”不适用于负数。
测试代码:
#include <stdio.h>
int main (void)
{ int i;
size_t uzs = 1;
ssize_t zs = -1;
for ( i= 0; i<5 ;i++, uzs <<= 16,zs <<= 16 )
{
printf ("%zu\t", uzs); /*true*/
printf ("%zd\t", uzs); /*true*/
printf ("%zu\t", zs); /* false*/
printf ("%zd\n", zs); /*true*/
}
return 0;
}