Subtracting pointers: Which type to use to store the result?

K

Keith Thompson

pete said:
stathis said:
I do not understand what you mean by that restriction,

N869
4. Conformance
[#5] A strictly conforming program shall use only those
features of the language and library specified in this
International Standard.2) It shall not produce output
dependent on any unspecified, undefined, or implementation-
defined behavior, and shall not exceed any minimum
implementation limit.

5.2.4.1 Translation limits
[#1] The implementation shall be able to translate and
execute at least one program that contains at least one
instance of every one of the following limits:

-- 65535 bytes in an object (in a hosted environment only)

But an implementation that supports only 65535-byte objects could
still have make size_t and ptrdiff_t be 16 bits. size_t would be
enough to represent the size of any object, but pointer subtraction
could still overflow the range of ptrdiff_t. (Making ptrdiff_t 32
bits would avoid this problem, but it's not required.)
 
K

Keith Thompson

Christian Bau said:
Anyway, the result of taking a pointer difference _has_ type ptrdiff_t,
so if that isn't enough, then you are out of luck, and there is nothing
you can do. Storing into a type other then ptrdiff_t cannot possibly
help, because undefined behavior happened earlier.

Well, one possible consequence of the undefined behavior is that
storing the result into a type other than ptrdiff_t could help. But
it's certainly not something you should depend on (unless you care
only about implementations that support and document this specific
behavior).
 
P

pete

Keith said:
pete said:
stathis said:
I believe that in a conforming program
which doesn't excede minimum environmental limits,
you're OK with ptrdiff_t, in C99.

I do not understand what you mean by that restriction,

N869
4. Conformance
[#5] A strictly conforming program shall use only those
features of the language and library specified in this
International Standard.2) It shall not produce output
dependent on any unspecified, undefined, or implementation-
defined behavior, and shall not exceed any minimum
implementation limit.

5.2.4.1 Translation limits
[#1] The implementation shall be able to translate and
execute at least one program that contains at least one
instance of every one of the following limits:

-- 65535 bytes in an object (in a hosted environment only)

But an implementation that supports only 65535-byte objects could
still have make size_t and ptrdiff_t be 16 bits. size_t would be
enough to represent the size of any object, but pointer subtraction
could still overflow the range of ptrdiff_t. (Making ptrdiff_t 32
bits would avoid this problem, but it's not required.)

N869
7.18.3 Limits of other integer types
[#1] The following object-like macros205) specify the
minimum and maximum limits of integer types corresponding to
types defined in other standard headers.
[#2] Each instance of these macros shall be replaced by a
constant expression suitable for use in #if preprocessing
directives, and this expression shall have the same type as
would an expression that is an object of the corresponding
type converted according to the integer promotions. Its
implementation-defined value shall be equal to or greater in
magnitude (absolute value) than the corresponding value
given below, with the same sign.

-- limits of ptrdiff_t
PTRDIFF_MIN -65535
PTRDIFF_MAX +65535
 
J

Jordan Abel

pete said:
stathis said:
I believe that in a conforming program
which doesn't excede minimum environmental limits,
you're OK with ptrdiff_t, in C99.

I do not understand what you mean by that restriction,

N869
4. Conformance
[#5] A strictly conforming program shall use only those
features of the language and library specified in this
International Standard.2) It shall not produce output
dependent on any unspecified, undefined, or implementation-
defined behavior, and shall not exceed any minimum
implementation limit.

5.2.4.1 Translation limits
[#1] The implementation shall be able to translate and
execute at least one program that contains at least one
instance of every one of the following limits:

-- 65535 bytes in an object (in a hosted environment only)

But an implementation that supports only 65535-byte objects could
still have make size_t and ptrdiff_t be 16 bits. size_t would be
enough to represent the size of any object, but pointer subtraction
could still overflow the range of ptrdiff_t. (Making ptrdiff_t 32
bits would avoid this problem, but it's not required.)

You _could_ cancel it out by having twos-complement wraparound and
having the offset bits of a pointer [which would wrap in such a way] to
a large object be 16 bits.
 
P

pete

Jordan said:
But an implementation that supports only 65535-byte objects could
still have make size_t and ptrdiff_t be 16 bits. size_t would be
enough to represent the size of any object, but pointer subtraction
could still overflow the range of ptrdiff_t. (Making ptrdiff_t 32
bits would avoid this problem, but it's not required.)

You _could_ cancel it out by having twos-complement wraparound and
having the offset bits of a pointer
[which would wrap in such a way] to
a large object be 16 bits.

ptrdiff_t can't be 16 bits in C99,
which was the standard that I mentioned.

In C89, there's hardly anything guaranteed about ptrdiff_t.
 
K

Keith Thompson

pete said:
Keith Thompson wrote: [...]
But an implementation that supports only 65535-byte objects could
still have make size_t and ptrdiff_t be 16 bits. size_t would be
enough to represent the size of any object, but pointer subtraction
could still overflow the range of ptrdiff_t. (Making ptrdiff_t 32
bits would avoid this problem, but it's not required.)
N869
[...]
-- limits of ptrdiff_t
PTRDIFF_MIN -65535
PTRDIFF_MAX +65535

Well, never mind, then.

Ok, so ptrdiff_t has to be at least 17 bits. If we assume the sizes
of all fundamental types are powers of two, ptrdiff_t will be at least
32 bits, and the risk of overflow occurs only for objects between 2GB
and 4GB. If objects bigger than 4GB are supported, then both size_t
and ptrdiff_t will probably be 64 bits, and this problem will only
occur for objects bigger than (I think) 8 exabytes.

(The everything-is-a-power-of-two assumption is not, of course,
something guaranteed by the standard, but it's probably a good
guideline for guessing where problems may occur in practice.)
 
P

pete

Keith said:
pete said:
Keith Thompson wrote: [...]
But an implementation that supports only 65535-byte objects could
still have make size_t and ptrdiff_t be 16 bits. size_t would be
enough to represent the size of any object, but pointer subtraction
could still overflow the range of ptrdiff_t. (Making ptrdiff_t 32
bits would avoid this problem, but it's not required.)
N869
[...]
-- limits of ptrdiff_t
PTRDIFF_MIN -65535
PTRDIFF_MAX +65535

Well, never mind, then.

Ok, so ptrdiff_t has to be at least 17 bits.

I can't find anything in C90 that requires ptrdiff_t
to be more than 8 bits.
 
M

Micah Cowan

Keith Thompson said:
Well, one possible consequence of the undefined behavior is that
storing the result into a type other than ptrdiff_t could help. But
it's certainly not something you should depend on (unless you care
only about implementations that support and document this specific
behavior).

I don't think I get what you're saying. How could storing the result
into a type other than ptrdiff_t possibly help with the UB problem?
The subtraction operation itself produces a ptrdiff_t, regardless of
what type you then convert it to for storage. If the result wouldn't
fit into a ptrdiff_t, then you invoke UB, regardless of what variable
type you're assigning to.
 
J

Jordan Abel

I don't think I get what you're saying. How could storing the result
into a type other than ptrdiff_t possibly help with the UB problem?
The subtraction operation itself produces a ptrdiff_t, regardless of
what type you then convert it to for storage. If the result wouldn't
fit into a ptrdiff_t, then you invoke UB, regardless of what variable
type you're assigning to.

Yes, but since a system can do whatever it wants for UB, it might decide
"Let's be silly today and actually have it _not_ break"
 
K

Keith Thompson

Micah Cowan said:
I don't think I get what you're saying. How could storing the result
into a type other than ptrdiff_t possibly help with the UB problem?
The subtraction operation itself produces a ptrdiff_t, regardless of
what type you then convert it to for storage. If the result wouldn't
fit into a ptrdiff_t, then you invoke UB, regardless of what variable
type you're assigning to.

Right, and as I already said, one possible consequence of undefined
behavior is that everything magically works just the way you want it
to. I'm not saying it's likely, just that it's possible; given UB,
*anything* is possible. (I was (weakly) refuting Christian Bau's
statement that it "cannot possibly help"; I wasn't claiming that it
would avoid undefined behavior.)
 
M

Micah Cowan

Jordan Abel said:
Yes, but since a system can do whatever it wants for UB, it might decide
"Let's be silly today and actually have it _not_ break"

Oh! Got it. =-)

-Micah
 
C

Christian Bau

Micah Cowan said:
I don't think I get what you're saying. How could storing the result
into a type other than ptrdiff_t possibly help with the UB problem?
The subtraction operation itself produces a ptrdiff_t, regardless of
what type you then convert it to for storage. If the result wouldn't
fit into a ptrdiff_t, then you invoke UB, regardless of what variable
type you're assigning to.

He is saying that the undefined behavior might be that you get the
correct result.

char* p = malloc (3000000000);
char* q = p + 3000000000;
size_t diff = q - p;

There could be implementations where storing a pointer difference into a
size_t will _always_ give the correct result if the first pointer is >=
the second pointer, even if the result doesn't fit into ptrdiff_t, and
your implementation might give this guarantee.

Or an implementation could give a guarantee that a pointer difference,
immediately cast to long long, will always give the correct result, even
if the pointer difference doesn't fit into ptrdiff_t.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top