Velocity Reviews > C++ > Byte Address Arithmetic Debate

Frederick Gotham
Guest
Posts: n/a

 11-19-2006

There is a thread currently active on this newsgroup entitled:

"how to calculate the difference between 2 addresses ?"

The thread deals with calculating the distance, in bytes, between two
memory addresses. Obviously, this can only be done if the addresses refer
to elements or members of the same object (or base objects, etc.).

John Carson and I proposed two separate methods.

I disagree with John's solution, and John disagrees with mine. Therefore,
I'd like to present them both here and see what the audience thinks.

Firstly, we shall start off with a simple POD type:

struct MyPOD {
int a;
double b;
void *c;
short d;
bool e;
int f;
};

Given an object of this type, we shall calculate the distance, in bytes,
between the "b" member and the "e" member.

My own method is as follows:

reinterpret_cast<char const volatile*>(&obj.e)
- reinterpret_cast<char const volatile*>(&obj.b)

John's method is as follows:

reinterpret_cast<long unsigned>(&obj.e)
- reinterpret_cast<long unsigned(&obj.b);

In defence of my own method:

(1) Any byte address can be accurately stored in a char*.

In attack of John's method:

(1) The Standard doesn't necessitate the existance of an integer type
large enough to accomodate a memory address.
(2) Even if such a type exists, the subtraction need not yield the
correct answer (e.g. if each integer 1 represents half a byte, or a quarter
of a byte).

Of course, seeing as how _I_ started this thread, it may be a little biased
toward my own ends, but I hope we get to the bottom of this objectively.

--

Frederick Gotham

David Harmon
Guest
Posts: n/a

 11-19-2006
On Sun, 19 Nov 2006 20:05:11 GMT in comp.lang.c++, Frederick Gotham
<(E-Mail Removed)> wrote,
>Given an object of this type, we shall calculate the distance, in bytes,
>between the "b" member and the "e" member.

#include <cstddef>
offsetof(MyPOD, e) - offsetof(MyPOD, b)

Frederick Gotham
Guest
Posts: n/a

 11-19-2006
David Harmon:

> On Sun, 19 Nov 2006 20:05:11 GMT in comp.lang.c++, Frederick Gotham
><(E-Mail Removed)> wrote,
>>Given an object of this type, we shall calculate the distance, in bytes,
>>between the "b" member and the "e" member.

>
> #include <cstddef>
> offsetof(MyPOD, e) - offsetof(MyPOD, b)

I'll rephrase the question:

Given two memory addresses in the form of pointers -- pointer types which
may be different -- calculate the distance in bytes between them. The
pointers refer to parts of the same object.

--

Frederick Gotham

Salt_Peter
Guest
Posts: n/a

 11-19-2006

Frederick Gotham wrote:
> David Harmon:
>
> > On Sun, 19 Nov 2006 20:05:11 GMT in comp.lang.c++, Frederick Gotham
> ><(E-Mail Removed)> wrote,
> >>Given an object of this type, we shall calculate the distance, in bytes,
> >>between the "b" member and the "e" member.

> >
> > #include <cstddef>
> > offsetof(MyPOD, e) - offsetof(MyPOD, b)

>
>
> I'll rephrase the question:
>
> Given two memory addresses in the form of pointers -- pointer types which
> may be different -- calculate the distance in bytes between them. The
> pointers refer to parts of the same object.
>
> --
>
> Frederick Gotham

Not that i'm trying deliberately to be a pain in the attic, but what do
you mean by between them?
Thats not the same as offset.

struct test
{
int n;
int i;
};

The distance in bytes between a test instance.n and instance.i would be
zero assuming no padding is involved. Remember: To assume == makes an
ASS out of U and ME.

Frederick Gotham
Guest
Posts: n/a

 11-19-2006

Salt_Peter:

> Not that i'm trying deliberately to be a pain in the attic, but what do
> you mean by between them?

Let's say that a certain object is located at memory address 14.

Let's say that another object is located at memory address 18.

This distance between them is 4.

> Thats not the same as offset.
>
> struct test
> {
> int n;
> int i;
> };
>
> The distance in bytes between a test instance.n and instance.i would be
> zero assuming no padding is involved.

We're just looking for the amount of bytes between two addresses.

Let's say that &obj.n == Memory Byte Address 56
Let's say that &obj.i == Memory Byte Address 60

Therefore, the distance between them is 4 bytes.

> Remember: To assume == makes an
> ASS out of U and ME.

Should I understand that somehow?

--

Frederick Gotham

Greg
Guest
Posts: n/a

 11-20-2006

Frederick Gotham wrote:
> Salt_Peter:
>
> > Not that i'm trying deliberately to be a pain in the attic, but what do
> > you mean by between them?

>
>
> Let's say that a certain object is located at memory address 14.
>
> Let's say that another object is located at memory address 18.
>
> This distance between them is 4.
>
>
> > Thats not the same as offset.
> >
> > struct test
> > {
> > int n;
> > int i;
> > };
> >
> > The distance in bytes between a test instance.n and instance.i would be
> > zero assuming no padding is involved.

>
>
> We're just looking for the amount of bytes between two addresses.
>
> Let's say that &obj.n == Memory Byte Address 56
> Let's say that &obj.i == Memory Byte Address 60
>
> Therefore, the distance between them is 4 bytes.

There is no guarantee that converting a pointer to an integer value
will produce the logical address of the referenced object. So neither
of the two approaches is certain to be portable. In fact, the only
portable approach available is to use the offsetof macro - either to
calculate the distance between the start of a POD object and one of its
members, or between any two members of the same object:

std::abs( offsetof(MyPOD, e) - offsetof(MyPOD, b));

Greg

Frederick Gotham
Guest
Posts: n/a

 11-20-2006
Greg:

> There is no guarantee that converting a pointer to an integer value
> will produce the logical address of the referenced object. So neither
> of the two approaches is certain to be portable.

My claim is that the char* method is perfect.

#include <cstddef>

template<class A,class B>
std:trdiff_t BytesBetween(A const &a,B const &b)
{
return reinterpret_cast<char const volatile*>(&b)
- reinterpret_cast<char const volatile*>(&a);
}

Of course, both "a" and "b" must refer to parts of the same object.

--

Frederick Gotham

John Carson
Guest
Posts: n/a

 11-20-2006
"Frederick Gotham" <(E-Mail Removed)> wrote in message
news:XN28h.16163\$(E-Mail Removed)
> There is a thread currently active on this newsgroup entitled:
>
> "how to calculate the difference between 2 addresses ?"
>
> The thread deals with calculating the distance, in bytes, between two
> memory addresses. Obviously, this can only be done if the addresses
> refer to elements or members of the same object (or base objects,
> etc.).
>
> John Carson and I proposed two separate methods.
>
> I disagree with John's solution, and John disagrees with mine.
> Therefore, I'd like to present them both here and see what the
> audience thinks.

Just to be clear: I don't claim my approach is more correct than yours. I
think they both involve implementation-defined behavior according to the
Standard. Both will usually work in practice. My preference for converting
to an integer is more of an aesthetic one. The aesthetics may differ
depending on the exact nature of the problem.

> Firstly, we shall start off with a simple POD type:
>
> struct MyPOD {
> int a;
> double b;
> void *c;
> short d;
> bool e;
> int f;
> };
>
> Given an object of this type, we shall calculate the distance, in
> bytes, between the "b" member and the "e" member.
>
> My own method is as follows:
>
> reinterpret_cast<char const volatile*>(&obj.e)
> - reinterpret_cast<char const volatile*>(&obj.b)
>
> John's method is as follows:
>
> reinterpret_cast<long unsigned>(&obj.e)
> - reinterpret_cast<long unsigned(&obj.b);

I wish to cast it to a pointer-sized integer. This is not synonymous with
long unsigned. Indeed on Win64, long unsigned is smaller than pointer-sized
(crazy, I know), but a pointer-sized integer nevertheless exists.

> In defence of my own method:
>
> (1) Any byte address can be accurately stored in a char*.

Any pointer can be cast to char*. However, by Section 5.2.10/3:

"The mapping performed by reinterpret_cast is implementation-defined. [Note:
it might, or might not, produce a representation different from the original
value. ]"

This applies equally to my method.

> In attack of John's method:
>
> (1) The Standard doesn't necessitate the existance of an integer
> type large enough to accomodate a memory address.

True, but not an issue on most platforms.

> (2) Even if such a type exists, the subtraction need not yield the
> correct answer (e.g. if each integer 1 represents half a byte, or a
> quarter of a byte).

If your cast can produce "a representation different from the original
value", I don't see that it offers an advantage. Moreover, Section 5.2.10/4
says that the conversion to an integer value "is intended to be unsurprising
to those who know the addressing structure of the underlying machine", which
provides an assurance of sorts for my preferred approach.

Finally, I point out that the Standard doesn't guarantee an integer type
large enough to store the result of the subtraction (See Section 5.7/6).
Once again, both approaches rely on an implementation-defined feature (or on
the choice of suitable addresses to compare).

--
John Carson

Greg
Guest
Posts: n/a

 11-20-2006
Frederick Gotham wrote:
> Greg:
>
> > There is no guarantee that converting a pointer to an integer value
> > will produce the logical address of the referenced object. So neither
> > of the two approaches is certain to be portable.

>
>
> My claim is that the char* method is perfect.
>
> #include <cstddef>
>
> template<class A,class B>
> std:trdiff_t BytesBetween(A const &a,B const &b)
> {
> return reinterpret_cast<char const volatile*>(&b)
> - reinterpret_cast<char const volatile*>(&a);
> }
>
> Of course, both "a" and "b" must refer to parts of the same object.

In order to subtract pointer a from pointer b, both a and b must point
to the same kind of object and the objects that they point to, must
both be members of the same array. Since the BytesBetween() function
template observes neither of these requirements, there is no guarantee
that its behavior will be defined.

"Unless both pointers point to elements of the same array object, or
one past the last element of the array object, the behavior is
undefined." [§5.7/7]

C++ would not need the offsetof macro if there were another, portable
way to calculate the distance between two members of an object.

Greg

Kai-Uwe Bux
Guest
Posts: n/a

 11-20-2006
Greg wrote:

> C++ would not need the offsetof macro if there were another, portable
> way to calculate the distance between two members of an object.

That seems incorrect: the difficulty with the offsetof macro is the need for
compile-time evaluation. That makes it impossible to create an instance of
the struct type and measure offsets of its members. Thus, even if you had a
perfectly fine method of computing distances of members of an object, it
would not help in writing an offsetof macro.

Best

Kai-Uwe Bux

 Posting Rules You may not post new threads You may not post replies You may not post attachments You may not edit your posts BB code is On Smilies are On [IMG] code is On HTML code is OffTrackbacks are On Pingbacks are On Refbacks are Off Forum Rules

 Similar Threads Thread Thread Starter Forum Replies Last Post joshc C Programming 5 03-31-2005 02:23 AM Peter Java 3 08-05-2004 10:55 AM Jean-Daniel Gamache Java 0 07-14-2004 03:57 AM Andreas VHDL 1 05-04-2004 01:49 PM Bharat Bhushan Java 15 08-05-2003 07:52 PM