how to calculate the difference between 2 addresses ?

J

John Carson

In a little while said:

Cast each of them to an integer type and perform the subtraction.

To cover ever possible address value, you will need a pointer-sized integer
type and it will need to be unsigned.

Since it is unsigned, you can only subtract the smaller from the larger, so
you will need to do an if() test to establish which is smaller before doing
the subtraction.

PS. It aids readability if you repeat your question in the body of your
post.
 
S

Salt_Peter

In said:

That depends of the types at the addresses involved. If you attempt to
calculate the offset of 2 integers, for example, you need to substract
their corresponding address and then mutiply by sizeof(int) in order to
obtain a byte-size quantitative value (if thats what you are getting
at).

An object's pointer is bound to its type. Thats how a pointer does
++ptr to find the next element.
So you need to explain what you mean by difference between 2 addresses,
because in C++ speak, that means "in terms of the objects involved".

And you can forget using void* for that too.

#include <iostream>

template< typename T >
size_t difference(const T& r_lhs, const T& r_rhs)
{
return (&r_lhs - &r_rhs) * sizeof(T);
}

int main()
{
int m(0);
int* p_m = &m;
std::cout << "p_m = " << p_m << std::endl;
int o(0);
int* p_o = &o;
std::cout << "p_o = " << p_o << std::endl;

std::cout << "difference(p_m, p_o) in bytes: ";
std::cout << difference(p_m, p_o) << std::endl;
return 0;
}

/*
p_m = 0x7fff628c8c54
p_o = 0x7fff628c8c44
difference(p_m, p_o) in bytes: 16
*/

Please don't be confused by the above program. This is not something a
C++ programmer needs to do in typical C++ code. Also, a programmer
never relies on a primitive to have some given size.
 
G

Gianni Mariani

John said:
Cast each of them to an integer type and perform the subtraction.

what would you use that for ?
To cover ever possible address value, you will need a pointer-sized integer
type and it will need to be unsigned.
std::ptrdiff_t


Since it is unsigned, you can only subtract the smaller from the larger, so
you will need to do an if() test to establish which is smaller before doing
the subtraction.

who said it is unsigned ?
 
J

John Carson

Gianni Mariani said:
what would you use that for ?

I said how you could do it. If you want to know why you would want to do it,
I suggest you direct your question to the OP.
who said it is unsigned ?

Pointers are unsigned, so if you have a "pointer-sized integer type" it will
need to be unsigned in order to cover the full range of possible addresses.
A signed integer will only cover half the needed values.

Take Win32 as an example. A pointer is 32 bits and can therefore take any
value from 0 to 0xFFFFFFFF. To represent all those values in a 32 bit
integer, you need the integer to be unsigned. As a practical matter,
application programs generally run in the lower 2GB of memory, so a signed
integer will serve the purpose. Using an unsigned integer is nevertheless a
more robust approach.
 
F

Frederick Gotham

To calcualte the amount of bytes between two addresses:

#include <cstddef>
#include <cassert>

template<class A,class B>
std::ptrdiff_t BytesBetween(A const *const pa,B const *const pb)
{
assert(pa); assert(pb);

return pb - pa;
}


Of course, anyone worth half shiling would simply write:

(char const*)pa - (char const*)pb;

This behaviour of this code is undefined if the pointers do not point to
bytes, members or elements of the same object.

Someone else suggested casting to integer types -- the behaviour of this is
undefined by the C++ Standard (or at the most, implementation defined).
 
J

John Carson

Frederick Gotham said:
To calcualte the amount of bytes between two addresses:

#include <cstddef>
#include <cassert>

template<class A,class B>
std::ptrdiff_t BytesBetween(A const *const pa,B const *const pb)
{
assert(pa); assert(pb);

return pb - pa;
}

This doesn't give a byte measure. Further, it won't compile if A and B are
different types.
Of course, anyone worth half shiling would simply write:

(char const*)pa - (char const*)pb;

This behaviour of this code is undefined if the pointers do not point
to bytes, members or elements of the same object.

Someone else suggested casting to integer types -- the behaviour of
this is undefined by the C++ Standard (or at the most, implementation
defined).

It is certainly not undefined. Section 5.2.10/4 reads as follows:

"A pointer can be explicitly converted to any integral type large enough to
hold it. The mapping function is implementation-defined [Note: it is
intended to be unsurprising to those who know the addressing structure of
the underlying machine. ]"

This refers to a reinterpret_cast. By 5.4/5, a reinterpret_cast can be
performed using C-style cast notation.
 
F

Frederick Gotham

John Carson:
This doesn't give a byte measure. Further, it won't compile if A and B
are different types.


Wups you're right, I forgot the casts.

return (char const volatile*)pb - (char const volatile*)pa;

Someone else suggested casting to integer types -- the behaviour of
this is undefined by the C++ Standard (or at the most, implementation
defined).

It is certainly not undefined. Section 5.2.10/4 reads as follows:

"A pointer can be explicitly converted to any integral type large enough
to hold it. The mapping function is implementation-defined [Note: it is
intended to be unsurprising to those who know the addressing structure
of the underlying machine. ]"

This refers to a reinterpret_cast. By 5.4/5, a reinterpret_cast can be
performed using C-style cast notation.


1: Why would you cast to integer type when you can simply subtract
pointers?
2: The C++ Standard doesn't necessitate the existance of an integer type
which can hold a byte address accurately.
3: Even if such an integer type exists, the behaviour of performing
arithmetic upon the integer value and then casting back to a pointer type
is not defined by the C++ Standard.
 
J

John Carson

Frederick Gotham said:
John Carson:
It is certainly not undefined. Section 5.2.10/4 reads as follows:

"A pointer can be explicitly converted to any integral type large
enough to hold it. The mapping function is implementation-defined
[Note: it is intended to be unsurprising to those who know the
addressing structure of the underlying machine. ]"

This refers to a reinterpret_cast. By 5.4/5, a reinterpret_cast can
be performed using C-style cast notation.


1: Why would you cast to integer type when you can simply subtract
pointers?

You can't "simply subtract pointers" and get a byte measure without a cast
(unless you have char* pointers to begin with), so the advantage of pointers
is not obvious. Using integers is more natural when you are doing integer
arithmetic (as opposed to pointer arithmetic) on addresses.
2: The C++ Standard doesn't necessitate the existance of an integer
type which can hold a byte address accurately.

It also doesn't guarantee that std::ptrdiff_t or any other type can hold

(char const volatile*)pb - (char const volatile*)pa;

See Section 5.7/6.

On many platforms (Windows, in particular) there is a type that will hold a
byte address accurately. Indeed, Windows provides an integer type called
UINT_PTR which is specifically for this purpose.
3: Even if such an integer type exists, the behaviour of performing
arithmetic upon the integer value and then casting back to a pointer
type is not defined by the C++ Standard.

Nor is it defined if you work with a char* pointer. And who says that the
integer value is to be cast back to a pointer?
 
F

Frederick Gotham

John Carson:
You can't "simply subtract pointers" and get a byte measure without a
cast (unless you have char* pointers to begin with),

Correct.


so the advantage of
pointers is not obvious.


It's obvious to me... but then again I know what I'm doing.

Using integers is more natural when you are
doing integer arithmetic (as opposed to pointer arithmetic) on
addresses.


What planet are you on? I hope you don't work professionally as a C++
programmer, do you? Here's some code that will work perfectly:

struct MyPOD {
int a;
char b;
void *c;
double d;
} obj;

ptrdiff_t distance_a_to_d = (char*)&obj.d - (char*)&obj.a;


I'll give you the benefit of the doubt and pretend that the address of a byte
can be accurately stored in an unsigned long. Even still, the behaviour of
the following is undefined:

ptrdiff_t distance_a_to_d =
(long unsigned)&obj.d - (long unsigned)&obj.a;

The C++ Standard gives no indication whatsoever as to how an address should
be represented numerically. By adding 1 to the integer form of an address,
you could be adding half a byte for all you know, or a quarter of a byte, or
an eighth of a byte.

It also doesn't guarantee that std::ptrdiff_t or any other type can hold

(char const volatile*)pb - (char const volatile*)pa;


Of course it does. What do you think ptrdiff_t is for? Making candy-floss?

See Section 5.7/6.

On many platforms (Windows, in particular) there is a type that will
hold a byte address accurately. Indeed, Windows provides an integer type
called UINT_PTR which is specifically for this purpose.


Don't mention Windows to me. Microsoft and all of its programming practises
are utterly retarded.

I take any need to mention Microsoft as an argument in my favour.

Nor is it defined if you work with a char* pointer.


Of course it is. The address of any byte in memory (whether it be part of a
POD, intrinsic type, union, class object, whatever) can be accurately stored
in either of:

void*
char*
char signed*
char unsigned*
 
J

John Carson

Frederick Gotham said:
John Carson:



It's obvious to me... but then again I know what I'm doing.


What planet are you on? I hope you don't work professionally as a C++
programmer, do you?

Insults designed to cover up weakness in argument or to try to bully people
into sharing your personal preferences are out of place. You have made a
succession of false claims in previous posts and continue to make them in
this one. A better quality of argument would impress me. Insults don't. In
fact the combination of your rudeness and inaccuracy makes me reluctant to
converse with you.

The reference to "natural", by the way, does not imply that one approach is
correct and the other incorrect. Look up "natural" in a dictionary.
Here's some code that will work perfectly:

struct MyPOD {
int a;
char b;
void *c;
double d;
} obj;

ptrdiff_t distance_a_to_d = (char*)&obj.d - (char*)&obj.a;

It may work perfectly, but it has unspecified behaviour. By 5.2.10/7 of the
C++ Standard:

"A pointer to an object can be explicitly converted to a pointer to an
object of different type. Except that converting an rvalue of type "pointer
to T1" to the type "pointer to T2" (where T1 and T2 are object types and
where the alignment requirements of T2 are no stricter than those of T1) and
back to its original type yields the original pointer value, the result of
such a pointer conversion is unspecified."

Since your code does not convert back to the original type, the result is
unspecified.
I'll give you the benefit of the doubt and pretend that the address
of a byte can be accurately stored in an unsigned long. Even still,
the behaviour of the following is undefined:

ptrdiff_t distance_a_to_d =
(long unsigned)&obj.d - (long unsigned)&obj.a;

The right-hand side is not undefined, it is implementation-defined. I have
already given the passage from the Standard that says so. Assignment to the
left-hand side is then a matter of assigning one integral type to another,
which raises the standard issues associated with such assignments.
The C++ Standard gives no indication whatsoever as to how an address
should be represented numerically. By adding 1 to the integer form of
an address, you could be adding half a byte for all you know, or a
quarter of a byte, or an eighth of a byte.

True enough, but, as I have shown above, it likewise guarantees nothing
about what happens to address values when a pointer is cast to a new type
(except that casting it back unchanged gives the original value). Thus one
is forced to rely on details of the implementation when either approach is
used.
Of course it does. What do you think ptrdiff_t is for? Making
candy-floss?

No, it is for storing the result of pointer arithmetic. However, the
standard doesn't guarantee that it will be large enough to do so. By Section
5.7/6:

"When two pointers to elements of the same array object are subtracted, the
result is the difference of the subscripts of the two array elements. The
type of the result is an implementation-defined signed integral type; this
type shall be the same type that is defined as ptrdiff_t in the <cstddef>
header (18.1). As with any other arithmetic overflow, if the result does not
fit in the space provided, the behavior is undefined."
Don't mention Windows to me. Microsoft and all of its programming
practises are utterly retarded.

I see we have left the realm of rational discussion and you are now treating
us to a display of your bile.
I take any need to mention Microsoft as an argument in my favour.

That explains a lot.
Of course it is.

It isn't. See above. The result is only defined if you cast back to the
original pointer type without changing the value of the char* pointer. If
you change the value of the char* pointer before casting back, you are in
the realm of undefined behaviour.
The address of any byte in memory (whether it be
part of a POD, intrinsic type, union, class object, whatever) can be
accurately stored in either of:

void*
char*
char signed*
char unsigned*

"Accurately stored" is rather ambiguous. What is not defined is the end
result of the following three operations performed in succession:

1. Casting to any of the pointers you list.
2. Modifying the pointer value.
3. Casting back to the original pointer type.
 
F

Frederick Gotham

John Carson:
Insults designed to cover up weakness in argument or to try to bully
people into sharing your personal preferences are out of place. You have
made a succession of false claims in previous posts and continue to make
them in this one. A better quality of argument would impress me. Insults
don't. In fact the combination of your rudeness and inaccuracy makes me
reluctant to converse with you.


I'm sorry about my attitude, I got a little worked up; I'll try no let it
happen again. Here's how I see it:

My Method: Cast to char*, then subtract.
Your Method: Cast to integer type, then subtract.

My own view is that your method is flawed, and that mine is perfectly OK. I
think it would be interesting to put this to a vote. As soon as I post
this, I'm going to start a new thread about calculating the distance (in
bytes) between two addresses. I'll make every effort to put across your
position as objectively as possible.

It may work perfectly, but it has unspecified behaviour. By 5.2.10/7 of
the C++ Standard:

"A pointer to an object can be explicitly converted to a pointer to an
object of different type. Except that converting an rvalue of type
"pointer to T1" to the type "pointer to T2" (where T1 and T2 are object
types and where the alignment requirements of T2 are no stricter than
those of T1) and back to its original type yields the original pointer
value, the result of such a pointer conversion is unspecified."

Since your code does not convert back to the original type, the result
is unspecified.


It is well know, both in C and C++, that you can store any byte address in
a char*. This is so well known that people take it for granted and tend not
to remember where exactly it is mentioned in the Standard.

I propose that my code works perfectly.

The right-hand side is not undefined, it is implementation-defined.


You sure about that? Are you sure that the conversion from pointer to
integer type won't result in a trap value?

True enough, but, as I have shown above, it likewise guarantees nothing
about what happens to address values when a pointer is cast to a new
type (except that casting it back unchanged gives the original value).


Actually, the alignment requirements of the "casted to" type must not be
stricter.

By the way, you'll notice that no type has less strict alignment
requirements than a char.

No, it is for storing the result of pointer arithmetic. However, the
standard doesn't guarantee that it will be large enough to do so. By
Section 5.7/6:

"When two pointers to elements of the same array object are subtracted,
the result is the difference of the subscripts of the two array
elements. The type of the result is an implementation-defined signed
integral type; this type shall be the same type that is defined as
ptrdiff_t in the <cstddef> header (18.1). As with any other arithmetic
overflow, if the result does not fit in the space provided, the behavior
is undefined."


Hmm... I've never read it like that, I'll look into it.

It doesn't make much sense that the Standard would provide a type for
pointer arithmetic, and then simply say "Oh yeah, by the way, this isn't
guaranteed to work".

I'll start that new thread now in a minute...
 
J

John Carson

Frederick Gotham said:
I'm sorry about my attitude, I got a little worked up; I'll try no
let it happen again.

Thats OK. Happens to the best of us. Except for one point, I will reply in
your new thread.
It doesn't make much sense that the Standard would provide a type for
pointer arithmetic, and then simply say "Oh yeah, by the way, this
isn't guaranteed to work".

I don't see where the Standard provides "a type" for pointer arithmetic.
Pointer arithmetic can be done with any type provided both types are the
same. Of course, this doesn't normally give a byte measure. I would agree
that the section on reinterpret_cast seems to put a lot of conventional code
in the undefined category. Presumably, there was a reason for this in terms
of the range of architectures to which the Standard is meant to apply.
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top