{
char *a, *b;
printf("%lx\n",(b-a));
}
通常可行,实际上,我无法想象它会在32位或64位机器上发出警告或失败。但对于ANSI C和尺寸感知,这是正确的做法吗?我希望这些代码可以在每个平台上运行,包括非Unix和嵌入式系统。
答案 0 :(得分:22)
b - a
是ptrdiff_t
,您可以使用%td
格式的printf
进行打印。从规范部分6.5.6 添加运算符:
当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素;结果是两个数组元素的下标的差异。结果的大小是实现定义的,其类型(有符号整数类型)在
ptrdiff_t
标头中定义为<stddef.h>
。< / p>
对于printf
及相关函数,请参见第7.19.6节格式化输入/输出函数:
t
指定以下d
,i
, {{ 1}} ,o
,u
或x
转化说明符适用到X
或相应的无符号整数类型参数;或者以下ptrdiff_t
转换说明符适用于指向n
参数的指针。
我在规范中更多地探讨了一下,似乎表明两个指针的差异甚至可能不适合ptrdiff_t
,在这种情况下行为是未定义的:
J.2未定义的行为
- 减去两个指针的结果在ptrdiff_t
(6.5.6)类型的对象中无法表示。
虽然我无法想象可能出现的任何实施。我想您可以检查ptrdiff_t
中的PTRDIFF_MIN
和PTRDIFF_MAX
是否真的确定。
答案 1 :(得分:12)
b - a
的结果仅在a
和b
指向同一个char数组的元素时定义。此要求也可以解释为a
和b
指向属于同一对象的字节,因为每个对象都可以重新解释为char数组。
否则,结果未定义。即尝试减去这样的指针会导致未定义的行为。
定义结果后,它具有ptrdiff_t
类型。 ptrdiff_t
是一个typedef名称,隐藏在该typedef名称后面的类型是实现定义的。已知该类型已签名。
另请注意,即使指针指向同一数组的元素,C语言也不能保证ptrdiff_t
足以容纳任何减法的结果。如果指针距离类型ptrdiff_t
太远而无法容纳结果,则行为未定义。
即使在C99中,printf
也没有特定的ptrdiff_t
格式说明符,因此您可能最好将其转换为足够大的有符号整数类型并使用该类型的格式说明符
printf("%ld\n", (long) (b - a));
更正: C99确实有ptrdiff_t
的长度修饰符。在C99中打印结果的正确方法是
printf("%td\n", b - a);
请注意t
是长度修饰符。它可以与d
,o
,u
,x
或X
转换说明符结合使用,具体取决于您要获取的输出格式。在C89 / 90中,您仍然需要坚持使用足够大的签名类型。
P.S。你说你无法想象它在32位或64位机器上失败了。事实上,很容易想象(或实际制造它)失败。您会看到32位计算机上的ptrdiff_t
通常是32位类型。由于它是有符号类型,因此它只有31位可用于表示值的大小。如果你选择两个相距较远的指针(即需要32位代表“距离”),b - a
的结果将溢出并且将毫无意义。为了防止此故障,您需要在32位计算机上至少使用33位有符号ptrdiff_t
,在64位计算机上至少需要65位有符号ptrdiff_t
。实现通常不会这样做,它们只是使用标准中的“权限”来在溢出上产生未定义的行为。
答案 2 :(得分:5)
这是ptrdiff_t
。来自man stddef.h
:
ptrdiff_t Signed integer type of the result of subtracting two pointers.
使用%td
打印。
答案 3 :(得分:2)
由于您尚未初始化变量 a 和 b ,因此代码会提供未定义的行为。但除此之外, b-a 的类型是 ptrdiff_t ,它足以包含结果。如果你有足够现代的C,你可以用%tx 打印它。
如果您不想使用%tx ,则应将结果转换为实际匹配(而不仅仅是偶然)您的格式说明符:
printf("%lx", (unsigned long)(a-b));
系统可能具有例如32位地址空间和32位ptrdiff_t,但是64位长,然后你的printf会失败,这是不可想象的。
答案 4 :(得分:2)
b-a的类型是ptrdiff_t