{
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.
b - a
is a ptrdiff_t
, which you can print with %td
in your printf
format. From the spec section 6.5.6 Additive operators:
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is
ptrdiff_t
defined in the<stddef.h>
header.
For printf
and related functions, section 7.19.6 Formatted input/output functions:
t
Specifies that a followingd
,i
,o
,u
,x
, orX
conversion specifier applies to aptrdiff_t
or the corresponding unsigned integer type argument; or that a followingn
conversion specifier applies to a pointer to aptrdiff_t
argument.
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:
J.2 Undefined behavior
- The result of subtracting two pointers is not representable in an object of typeptrdiff_t
(6.5.6).
Though I can't imagine any implementation where that might come up. I guess you could check PTRDIFF_MIN
and PTRDIFF_MAX
in <stdint.h>
to be really sure.
The result of b - a
is only defined when both a
and b
point to elements of the same char array. This requirement can also be interpreted as a
and b
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 type ptrdiff_t
to accomodate the result, the behavior is undefined.
There's no specific printf
format specifier for ptrdiff_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 type
printf("%ld\n", (long) (b - a));
Correction: C99 does have a length modifier for ptrdiff_t
. The proper way to print the result in C99 would be
printf("%td\n", b - a);
Note that t
is a length modifier. It can be combined with d
, o
, u
, x
or X
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 of b - a
will overflow and will be meaningless. In order to prevent this failure you'd need at least 33-bit signed ptrdiff_t
on a 32-bit machine, and at least 65-bit signed ptrdiff_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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With