C 字符*a,*b;什么类型是(b-a)以及如何打印?

C 字符*a,*b;什么类型是(b-a)以及如何打印?,c,pointers,stdio,C,Pointers,Stdio,通常是有效的,事实上,我无法想象它会在32位或64位机器上发出警告或出现故障。但是,对于ANSI C和尺寸意识来说,这是正确的做法吗?我希望此代码能够在所有可能的平台上运行,包括非Unix和嵌入式系统。由于您尚未初始化变量a和b,因此代码给出了未定义的行为。但除此之外,b-a的类型是ptrdiff\u t,其大小足以包含结果。如果你有足够现代的C,你可以用%tx打印它 如果不想使用%tx,则应转换结果,使其与格式说明符实际匹配(并非偶然): { char *a, *b; printf(

通常是有效的,事实上,我无法想象它会在32位或64位机器上发出警告或出现故障。但是,对于ANSI C和尺寸意识来说,这是正确的做法吗?我希望此代码能够在所有可能的平台上运行,包括非Unix和嵌入式系统。

由于您尚未初始化变量ab,因此代码给出了未定义的行为。但除此之外,b-a的类型是ptrdiff\u t,其大小足以包含结果。如果你有足够现代的C,你可以用%tx打印它

如果不想使用%tx,则应转换结果,使其与格式说明符实际匹配(并非偶然):

{
  char *a, *b;

  printf("%lx\n",(b-a));
}

例如,一个系统可能有一个32位的地址空间和一个32位的ptrdiff,但有一个64位的长度,然后您的printf就会失败,这不是不可想象的。

这是
ptrdiff\t
。从
man stddef.h

printf("%lx", (unsigned long)(a-b));
ptrdiff\t 两个指针相减结果的有符号整数类型。
使用
%td
b-a
是一种
ptrdiff\u t
,您可以使用
%td
printf
格式打印。根据规范第6.5.6节“加法运算符”:

当减去两个指针时,两个指针都应指向同一数组对象的元素,或指向数组对象最后一个元素之后的元素;结果是两个数组元素的下标不同。结果的大小由实现定义,其类型(有符号整数类型)是在
头中定义的
ptrdiff\u t

对于
printf
和相关功能,第7.19.6节格式化输入/输出功能:

t
指定以下
d
i
o
u
x
,或
X
转换说明符应用于
ptrdiff\u t
或相应的无符号整数类型参数;或者以下转换说明符应用于指向参数的指针

我在规范中又翻了几遍,它似乎表明两个指针的差异甚至可能不适合
ptrdiff\u t
,在这种情况下,行为是未定义的:

J.2未定义的行为
-减去两个指针的结果不能在类型为
ptrdiff\u t
(6.5.6)的对象中表示


尽管我无法想象在哪里会出现这样的实现。我想你可以在
中检查
PTRDIFF\u MIN
PTRDIFF\u MAX
来确定。

只有当
a
b
都指向相同字符数组的元素时,才能定义
b-a
的结果。这一要求也可以解释为
a
b
指向属于同一对象的字节,因为每个对象都可以重新解释为字符数组

否则,结果是未定义的。即,尝试减去此类指针会导致未定义的行为

定义结果时,它具有
ptrdiff\u t
类型
ptrdiff_t
是一个typedef名称,该typedef名称后面隐藏的类型由实现定义。但已知该类型已签名

还要注意的是,C语言不能保证
ptrdiff\u t
足够大以容纳任何减法运算的结果,即使指针指向同一数组的元素也是如此。如果指针距离太远,类型
ptrdiff\u t
无法容纳结果,则行为未定义

即使在C99中,
ptrdiff\u t
也没有特定的
printf
格式说明符,因此最好将其转换为足够大的有符号整数类型,并为该类型使用格式说明符

ptrdiff_t Signed integer type of the result of subtracting two pointers. 更正:C99确实有一个长度修饰符用于
ptrdiff\u t
。在C99中打印结果的正确方法是

printf("%ld\n", (long) (b - a));
请注意,
t
是一个长度修饰符。它可以与
d
o
u
x
x
转换说明符组合,具体取决于您想要获得的输出格式。在C89/90中,您仍然必须坚持使用足够大的有符号类型


p.S.您说过您无法想象它在32位或64位机器上会失败。事实上,很容易想象(或实际做到)失败。您可以看到32位机器上的
ptrdiff\u t
通常是32位类型。由于它是有符号类型,因此只有31位可用于表示值的大小。如果取两个相距较远的指针(即需要32位来表示“距离”),则
b-a
的结果将溢出且无意义。为了防止此故障,在32位机器上至少需要33位有符号的
ptrdiff\u t
,在64位机器上至少需要65位有符号的
ptrdiff\u t
。实现通常不会这样做,它们只是使用标准中的“权限”在溢出上产生未定义的行为。

b-a的类型是

@Nikolai:谢谢。我一定是喝醉了。我的C有多现代?我现在的C有它,但是我击中一个没有它的C的机会有多大?什么时候将%tx添加到规范中?什么是“足够大”?铸造一个长似乎“足够大”乍一看,有一个系统的指针将不适合在一个长,并需要一个长?显然,在32位系统上,long是32位的,因此足够大,而在64位系统上,long是64位的
printf("%td\n", b - a);