字符*a,*b; (ba) 是什么类型以及如何打印它?
{
char *a, *b;
printf("%lx\n",(b-a));
}
通常可以工作,事实上,我无法想象它在 32 位或 64 位机器上发出警告或失败。但这对于 ANSI C 和大小认识来说是正确的做法吗?我希望这段代码能够在所有可能的平台上运行,包括非 Unix 和嵌入式系统。
{
char *a, *b;
printf("%lx\n",(b-a));
}
Usually works, in fact, I can't imagine it giving a warning or failing on a 32-bit or 64-bit machine. But is that the proper thing to do for ANSI C and size awareness? I'd like this code to work on every platform possible, including non-Unixes and embedded systems.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
b - a
是ptrdiff_t
,您可以使用%td
以printf
格式打印它。根据规范第 6.5.6 节加法运算符:对于
printf
和相关函数,第 7.19.6 节格式化输入/输出函数:我又仔细研究了规范,似乎表明两个指针的差异甚至可能不适合 ptrdiff_t ,在这种情况下,行为是未定义的:
尽管我无法想象可能出现的任何实现。我想您可以检查
中的PTRDIFF_MIN
和PTRDIFF_MAX
来确定。b - a
is aptrdiff_t
, which you can print with%td
in yourprintf
format. From the spec section 6.5.6 Additive operators:For
printf
and related functions, section 7.19.6 Formatted input/output functions:I poked around in the spec some more, and it seems to indicate that a difference of two pointers might not even fit in a
ptrdiff_t
, in which case behaviour is undefined:Though I can't imagine any implementation where that might come up. I guess you could check
PTRDIFF_MIN
andPTRDIFF_MAX
in<stdint.h>
to be really sure.仅当
a
和b
都指向同一 char 数组的元素时才定义b - a
的结果。此要求也可以解释为a
和b
指向属于同一对象的字节,因为每个对象都可以重新解释为 char 数组。否则,结果是不确定的。即尝试减去此类指针会导致未定义的行为。
当结果被定义时,它具有
ptrdiff_t
类型。 ptrdiff_t 是一个 typedef 名称,该 typedef 名称后面隐藏的类型是实现定义的。但已知该类型是有符号的。另请注意,C 语言不保证 ptrdiff_t 足够大以容纳任何减法的结果,即使指针指向同一数组的元素也是如此。如果指针相距太远,
ptrdiff_t
类型无法容纳结果,则行为未定义。即使在 C99 中,
ptrdiff_t
也没有特定的printf
格式说明符,因此您最好将其转换为足够大的有符号整数类型,并为此使用格式说明符类型更正: C99 确实有一个
ptrdiff_t
的长度修饰符。在 C99 中打印结果的正确方法是注意
t
是长度修饰符。它可以与d
、o
、u
、x
或X
转换结合使用说明符,具体取决于您想要获得的输出格式。在 C89/90 中,您仍然必须坚持使用足够大的有符号类型。PS 你说你无法想象它在 32 位或 64 位机器上失败。事实上,很容易想象(或实际实现)失败。您会看到 32 位机器上的 ptrdiff_t 通常是 32 位类型。由于它是有符号类型,因此只有 31 位可用于表示值的大小。如果你取两个相距较远的指针(即需要32位来表示“距离”),
b - a
的结果将会溢出并且毫无意义。为了防止出现此故障,您在 32 位计算机上至少需要 33 位签名的ptrdiff_t
,在 64 位计算机上至少需要 65 位签名的ptrdiff_t
机器。实现通常不会这样做,它们只是使用标准中的“权限”来在溢出时产生未定义的行为。The result of
b - a
is only defined when botha
andb
point to elements of the same char array. This requirement can also be interpreted asa
andb
pointing to bytes belonging to the same object, since every object can be re-interpreted as a char array.Otherwise, the result is undefined. I.e. an attempt to subtract such pointers results in undefined behavior.
When the result is defined, it has
ptrdiff_t
type.ptrdiff_t
is a typedef name and what type is hiding behind that typedef name is implementation-defined. The type is known to be signed though.Also note, that C language does not guarantee that
ptrdiff_t
is large enough to hold the result of any subtraction, even if the pointers are pointing to the elements of the same array. If the pointers are too far apart for the typeptrdiff_t
to accomodate the result, the behavior is undefined.There's no specific
printf
format specifier forptrdiff_t
even in C99, so you'll probably be better off converting it to a sufficiently large signed integer type and use a format specifier for that typeCorrection: C99 does have a length modifier for
ptrdiff_t
. The proper way to print the result in C99 would beNote that
t
is a length modifier. It can be combined withd
,o
,u
,x
orX
conversion specifiers, depending on what output format you want to obtain. In C89/90 you would still have to stick with using a sufficiently large signed type.P.S. You said that you can't imagine it failing on a 32-bit or 64-bit machine. In fact, it is very easy to imagine (or to actually make it) fail. You see the
ptrdiff_t
on a 32-bit machine is usually a 32-bit type. Since it is a signed type, it has only 31 bit available to represent the magnitude of the value. If you take two pointers that are farther apart (i.e. require 32 bits to represent the "distance"), the result ofb - a
will overflow and will be meaningless. In order to prevent this failure you'd need at least 33-bit signedptrdiff_t
on a 32-bit machine, and at least 65-bit signedptrdiff_t
on 64-bit machine. Implementations normally don't do that, they just use the "permission" from the standard to produce undefined behavior on the overflow.它是
ptrdiff_t
。来自man stddef.h
:使用
%td
打印它。It's
ptrdiff_t
. Fromman stddef.h
:Print it with
%td
.ba 的类型为 ptrdiff_t
The type of b-a is ptrdiff_t
由于您尚未初始化变量 a 和 b,因此代码会给出未定义的行为。但除此之外,ba的类型是ptrdiff_t,它足够大以包含结果。如果你有足够现代的 C,你可以使用 %tx 来打印它。
如果您不想使用 %tx,您应该转换您的结果,使其实际上与您的格式说明符匹配(而不是偶然):
系统可能具有例如32 位地址空间和 32 位 ptrdiff_t,但长度是 64 位,然后你的 printf 就会失败。
Since you haven't initialized the variables a and b, the code gives undefined behavior. But other than that, the type of b-a is ptrdiff_t, which is big enough to contain the result. If you have a modern enough C, you can printf it with %tx.
If you don't want to use %tx, you should convert your result so it actually matches (and not just by accident) your format specifier:
It is not inconceivable that a system could have for example a 32-bit address space, and a 32-bit ptrdiff_t, but a 64-bit long, and then your printf would fail.