Velocity Reviews > difference between pointers

# difference between pointers

Varun Tewari
Guest
Posts: n/a

 03-30-2013
hello all,

consider the following code.

int a,b,d1,d2,diff;

d1= &a;
d2 = &b;
diff = &a-&b;
printf("\nDifference between address: %d", diff);
diff = d1-d2;
printf("\nDifference between address(stored in integers): %d", diff);

ideally, both printf should result same output.
but as expected diff = d1-d2 gives 4.
but diff = &a-&b gives 1.

Why so when C doesn't really support operator overloading.

Eric Sosman
Guest
Posts: n/a

 03-30-2013
On 3/30/2013 11:36 AM, Varun Tewari wrote:
> hello all,
>
> I get this doubt about this behavior of C.
>
> consider the following code.
>
> int a,b,d1,d2,diff;
>
> d1= &a;
> d2 = &b;
> diff = &a-&b;
> printf("\nDifference between address: %d", diff);
> diff = d1-d2;
> printf("\nDifference between address(stored in integers): %d", diff);
>
> ideally, both printf should result same output.
> but as expected diff = d1-d2 gives 4.
> but diff = &a-&b gives 1.
>
> Why so when C doesn't really support operator overloading.

The short (and technical, and not very helpful) answer is
that the code's behavior is undefined: The C language doesn't
specify what should happen, so *anything* might happen.

A longer answer ...

First, pointer arithmetic always operates in units of the
pointed-at type. Adding 1 to an `int*' advances the pointer
to the next `int', adding 1 to a `double*' advances to the next
`double', and so on. Even if an `int' occupies four bytes and
a `double' occupies eight, adding 1 advances the pointer by the
proper distance for its type.

... so subtraction works the same way: If you start with an
`int*', add 1 to produce another pointer to the next `int', and
then subtract the two values, what do you get? You get 1: the
distance between the two objects is expressed in multiples of
the object size. If you start with a pointer `p' and derive a
new pointer `q' by computing `q = p + 3', it should come as no
surprise that `q - p' yields 3.

However, this adding and subtracting only works when you're
navigating within in an array that contains the pointed-at objects.
That's the only way to be sure of the right adjacency and spacing
that allows pointer arithmetic to be defined. Consider: If you
have two objects that are six bytes long, and if they exist at
addresses eight bytes apart, the distance between them is not a
multiple of the size and pointer arithmetic falls down: You can't
add 1 to a pointer and have it advance by one-and-a-third objects!

... and that's where the undefined behavior enters your code.
Since `a' and `b' are free-standing objects, unrelated to each
other and not part of the same array, subtracting pointers to them
cannot be guaranteed to produce a sensible answer. So C does not
promise that anything sensible will happen; C says "the behavior
is undefined" and just leaves it at that. In your case it seems
that `a' and `b' did in fact wind up in adjacent memory regions,
but that's a coincidence, not something C promises nor that you
can rely on.

Next topic: Why 1 vs. 4?

C promises that a pointer can be converted to some kind of
integer, but says very little about how wide an integer is needed
and says nothing at all about the nature of the conversion. You
take a pointer, convert it to an `int', and you get some kind of
value. (It is not even guaranteed that you'll get the same value
every time!) In your case, it seems that the address part of your
pointer (or part of it) simply got transliterated into a bag of
bits that were then interpreted as an `int' value -- that's a very
common scheme, but not the only one.

But notice what's left behind: The pointer "knew" what kind
of object it pointed to, and hence the size of that object, and
thus knew how to compensate for that size when doing arithmetic.
The `int' resulting from conversion, though, has no information
about the type of object the pointer aimed at, and cannot make
adjustments for object size. So when you subtract the integers
there's no adjustment: You get the distance between the objects
expressed not in object-units, but in bytes (again, this is a
common outcome but not the only possibility).

Pointers are not "just addresses," but "addresses with type."

--
Eric Sosman
http://www.velocityreviews.com/forums/(E-Mail Removed)d

Tim Rentsch
Guest
Posts: n/a

 03-30-2013
Varun Tewari <(E-Mail Removed)> writes:

> hello all,
>
> I get this doubt about this behavior of C.
>
> consider the following code.
>
> int a,b,d1,d2,diff;
>
> d1= &a;
> d2 = &b;
> diff = &a-&b;
> printf("\nDifference between address: %d", diff);
> diff = d1-d2;
> printf("\nDifference between address(stored in integers): %d", diff);
>
> ideally, both printf should result same output.
> but as expected diff = d1-d2 gives 4.
> but diff = &a-&b gives 1.
>
> Why so when C doesn't really support operator overloading.

Compiling this code should have produced at least one warning or
error message. If it did not, you are very likely operating the
compiler in a non-conforming mode; in other words, the language
accepted may look a lot like C, but it isn't C.

If the compiler you are using is gcc, try these options:

gcc -ansi -pedantic-errors

which directs gcc to operate according to how standard C is
defined, rather than the "C-like but not C" language that
gcc accepts by default.

Tim Rentsch
Guest
Posts: n/a

 03-30-2013
Eric Sosman <(E-Mail Removed)> writes:

> On 3/30/2013 11:36 AM, Varun Tewari wrote:
>> hello all,
>>
>> I get this doubt about this behavior of C.
>>
>> consider the following code.
>>
>> int a,b,d1,d2,diff;
>>
>> d1= &a;
>> d2 = &b;
>> diff = &a-&b;
>> printf("\nDifference between address: %d", diff);
>> diff = d1-d2;
>> printf("\nDifference between address(stored in integers): %d", diff);
>>
>> ideally, both printf should result same output.
>> but as expected diff = d1-d2 gives 4.
>> but diff = &a-&b gives 1.
>>
>> Why so when C doesn't really support operator overloading.

>
> The short (and technical, and not very helpful) answer is
> that the code's behavior is undefined: The C language doesn't
> specify what should happen, so *anything* might happen.

Except that, before getting to that point, a diagnostic is
required -- assigning an integer to a pointer is a constraint
violation.

> [snip]
>
> C promises that a pointer can be converted to some kind of
> integer, but says very little about how wide an integer is needed
> and says nothing at all about the nature of the conversion. You
> take a pointer, convert it to an `int', and you get some kind of
> value. (It is not even guaranteed that you'll get the same value
> every time!) In your case, it seems that the address part of your
> pointer (or part of it) simply got transliterated into a bag of
> bits that were then interpreted as an `int' value -- that's a very
> common scheme, but not the only one.

This is right in spirit but a lot of the details are wrong.

C does promise that a pointer can be converted to one particular
integer type; however, the conversion is completely specified,
as is the width of the integer, because the type in question is
the "boolean" type _Bool. The Standard does not guarantee that
a pointer can be converted to any other integer type.

If the header file <stdint.h> defines the types [u]intptr_t,
then these types are guaranteed to work for converting any valid
pointer to void (ie, any valid pointer value of type 'void *');
moreover, converting back the other direction is guaranteed to
compare equal to the original pointer value.

There is no guarantee that a pointer to any type other than
void can be converted to any integer type other than _Bool. A
pointer to void can be converted to the types [u]intptr_t, but
only if the implementation defines them, which the Standard
does not require.

On the flip side, the result of converting a pointer to an
integer type is implementation-defined, which means each
implementation has to document what it does. So, for any
specific implementation, you can find out which integer types
may be used to convert different kinds of pointer values, and
what the result of those conversions will be.

Keith Thompson
Guest
Posts: n/a

 03-30-2013
Eric Sosman <(E-Mail Removed)> writes:
> On 3/30/2013 11:36 AM, Varun Tewari wrote:
>> I get this doubt about this behavior of C.
>>
>> consider the following code.
>>
>> int a,b,d1,d2,diff;
>>
>> d1= &a;
>> d2 = &b;
>> diff = &a-&b;
>> printf("\nDifference between address: %d", diff);
>> diff = d1-d2;
>> printf("\nDifference between address(stored in integers): %d", diff);

[SNIP]
> Next topic: Why 1 vs. 4?
>
> C promises that a pointer can be converted to some kind of
> integer, but says very little about how wide an integer is needed
> and says nothing at all about the nature of the conversion. You
> take a pointer, convert it to an `int', and you get some kind of
> value. (It is not even guaranteed that you'll get the same value
> every time!) In your case, it seems that the address part of your
> pointer (or part of it) simply got transliterated into a bag of
> bits that were then interpreted as an `int' value -- that's a very
> common scheme, but not the only one.

You're assuming that this:

d1 = &a; /* where d1 and a are both of type int */

specifies a conversion. Nothing in the C standard says or implies
that. The types int and int* are not assignment-compatible, so
the assignment is a constraint violation, requiring a diagnostic.
*If* the compiler chooses to generate an executable after issuing
the diagnostic, nothing in the C standard says anything about how
it behaves.

It happens that, in most implementations, the behavior is equivalent
to:

d1 = (int)&a;

for historical reasons. But you shouldn't depend on that; a
conforming implementation could do *anything*. Don't waste your
time running the program, just fix the source code.

And in this case, the best fix is almost certainly *not* to add
the cast (adding casts to silence warnings is rarely a good idea),
but to change the declaration of d1.

(I'm leaving aside the fact that the behavior of `&a - &b` is
undefined; others have covered that.)

[...]

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

BartC
Guest
Posts: n/a

 03-30-2013

"Varun Tewari" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> hello all,
>
> I get this doubt about this behavior of C.
>
> consider the following code.
>
> int a,b,d1,d2,diff;
>
> d1= &a;
> d2 = &b;
> diff = &a-&b;
> printf("\nDifference between address: %d", diff);
> diff = d1-d2;
> printf("\nDifference between address(stored in integers): %d", diff);
>
> ideally, both printf should result same output.
> but as expected diff = d1-d2 gives 4.
> but diff = &a-&b gives 1.
>
> Why so when C doesn't really support operator overloading.

I don't understand what overloading has to do with it.

C likes to do pointer arithmetic in terms of 'objects' rather than bytes.
&a-&b gives the difference in number of objects (and a, b happen to be next
to each in memory, so one object difference).

While d1-d2 subtracts one byte address from another, after each is converted
to a plain int so that it no longer knows what kinds of pointers they were.

It would be a little more interesting if a and b weren't aligned on a 4-byte
boundary, and the byte-difference in their addresses wasn't a multiple of 4.
(For this sort of reason, I'd have preferred pointer arithmetic to work in
bytes, or rather chars, but using objects has its advantages too.)

--
Bartc

Tim Rentsch
Guest
Posts: n/a

 03-30-2013
Keith Thompson <(E-Mail Removed)> writes:

> Eric Sosman <(E-Mail Removed)> writes:
>> On 3/30/2013 11:36 AM, Varun Tewari wrote:
>>> I get this doubt about this behavior of C.
>>>
>>> consider the following code.
>>>
>>> int a,b,d1,d2,diff;
>>>
>>> d1= &a;
>>> d2 = &b;
>>> diff = &a-&b;
>>> printf("\nDifference between address: %d", diff);
>>> diff = d1-d2;
>>> printf("\nDifference between address(stored in integers): %d", diff);

> [SNIP]
>> Next topic: Why 1 vs. 4?
>>
>> C promises that a pointer can be converted to some kind of
>> integer, but says very little about how wide an integer is needed
>> and says nothing at all about the nature of the conversion. You
>> take a pointer, convert it to an `int', and you get some kind of
>> value. (It is not even guaranteed that you'll get the same value
>> every time!) In your case, it seems that the address part of your
>> pointer (or part of it) simply got transliterated into a bag of
>> bits that were then interpreted as an `int' value -- that's a very
>> common scheme, but not the only one.

>
> You're assuming that this:
>
> d1 = &a; /* where d1 and a are both of type int */
>
> specifies a conversion. Nothing in the C standard says or implies
> that. The types int and int* are not assignment-compatible, so
> the assignment is a constraint violation, requiring a diagnostic.
> *If* the compiler chooses to generate an executable after issuing
> the diagnostic, nothing in the C standard says anything about how
> it behaves. [...] a conforming implementation could do *anything*.
> [snip elaboration]

I'm not sure what your reasoning is to reach this conclusion.
Certainly this assignment has a constraint violation, but you're
saying, in effect, that it has undefined behavior. Presumably
the underlying reasoning is one of two things, namely:

A. There is a constraint violation, and any constraint
violation is necessarily undefined behavior; or

B. The assignment statement is trying to assign a pointer
type to an integer type, and nothing in the Standard
says how to do that, so there is undefined behavior.

IMO point A is incorrect, although I would agree the point
is debatable. Section 4 paragraph 3 says in part:

If a ``shall'' or ``shall not'' requirement that appears
outside of a constraint or runtime-constraint is violated,
the behavior is undefined.

This statement makes it reasonable to infer that a constraint
violation might _not_ result in undefined behavior in some
instances, as otherwise there is no point in excluding it.
("The exception proves the rule in cases not excepted.")

Turning to point B, I think it is clearly just wrong, because
of 6.5.16.1 p 2.

Aside from the constraint violation, I don't see anything that
makes this assignment have undefined behavior. If it is true
that a constraint violation is not /ipso facto/ undefined
behavior, then the behavior of this assignment is well-defined.
A compiler is free to reject it (with the necessary diagnostic)
because of the constraint violation; but if the compiler chooses
to accept it, then the assignment must behave the same way that

d1 = (int) &a;

would.

Varun Tewari
Guest
Posts: n/a

 03-31-2013
Yep it did give warning.Thnx for pointing the correct gcc option for correct ansi parsing.

Keith Thompson
Guest
Posts: n/a

 03-31-2013
Tim Rentsch <(E-Mail Removed)> writes:
> Keith Thompson <(E-Mail Removed)> writes:

[...]
>> You're assuming that this:
>>
>> d1 = &a; /* where d1 and a are both of type int */
>>
>> specifies a conversion. Nothing in the C standard says or implies
>> that. The types int and int* are not assignment-compatible, so
>> the assignment is a constraint violation, requiring a diagnostic.
>> *If* the compiler chooses to generate an executable after issuing
>> the diagnostic, nothing in the C standard says anything about how
>> it behaves. [...] a conforming implementation could do *anything*.
>> [snip elaboration]

>
> I'm not sure what your reasoning is to reach this conclusion.
> Certainly this assignment has a constraint violation, but you're
> saying, in effect, that it has undefined behavior. Presumably
> the underlying reasoning is one of two things, namely:
>
> A. There is a constraint violation, and any constraint
> violation is necessarily undefined behavior; or
>
> B. The assignment statement is trying to assign a pointer
> type to an integer type, and nothing in the Standard
> says how to do that, so there is undefined behavior.
>
> IMO point A is incorrect, although I would agree the point
> is debatable. Section 4 paragraph 3 says in part:
>
> If a ``shall'' or ``shall not'' requirement that appears
> outside of a constraint or runtime-constraint is violated,
> the behavior is undefined.

IMHO A is correct (programs with constraint violations have undefined
behavior), though I'm not sure I can prove it.

> This statement makes it reasonable to infer that a constraint
> violation might _not_ result in undefined behavior in some
> instances, as otherwise there is no point in excluding it.
> ("The exception proves the rule in cases not excepted.")

Perhaps, but only if the behavior is actually defined somewhere.

> Turning to point B, I think it is clearly just wrong, because
> of 6.5.16.1 p 2.

Which says:

In *simple assignment* (=), the value of the right operand is
converted to the type of the assignment expression and replaces the
value stored in the object designated by the left operand.

That's an interesting point, but consider the definition of "constraint"
in 3.8:

restriction, either syntactic or semantic, by which the exposition
of language elements is to be interpreted

So the statement about the semantics of a simplea ssignment "is to
be interpreted" in the context of the restriction on the operands.
My conclusion from that is that if the constraint is violated,
the statement doesn't apply.

If the constraint is violated, it isn't a simple assignment.
We don't know what it is, but it's not part of a valid C program.

A compiler is free to reject a program containing such an assignment.
If it does so, the conversion described in 6.5.16.1p2 does not
occur -- but that doesn't mean the compiler is non-conforming.

I suppose you could (and apparently do) interpret it to mean that
the conversion occurs *if* the program is not rejected. I find
that interpretation a bit strained.

> Aside from the constraint violation, I don't see anything that
> makes this assignment have undefined behavior. If it is true
> that a constraint violation is not /ipso facto/ undefined
> behavior, then the behavior of this assignment is well-defined.
> A compiler is free to reject it (with the necessary diagnostic)
> because of the constraint violation; but if the compiler chooses
> to accept it, then the assignment must behave the same way that
>
> d1 = (int) &a;
>
> would.

I disagree.

Note also that, quoting 4p6:

A conforming implementation may have extensions [...] provided they
do not alter the behavior of any strictly conforming program.

which implies that such an extension *could* alter the behavior of a
program containing such an assignment.

(It could also imply that an extension could alter the behavior
of printf("%d\n", INT_MAX), which I find a bit troubling. I'm not
sure that strict conformance was the best criterion to use there.)

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Joe Pfeiffer
Guest
Posts: n/a

 03-31-2013
"christian.bau" <(E-Mail Removed)> writes:

> On Mar 30, 3:36Â*pm, Varun Tewari <(E-Mail Removed)> wrote:
>> hello all,
>>
>> I get this doubt about this behavior of C.

>
> You don't have a doubt, you have a question. A "doubt" is a "feeling
> of uncertainty or lack of conviction".

There are areas of the world in which "doubt" is used exactly as
Americans and Europeans use "question". This was one of the things I
had to get used to when I started having significant numbers of students
from India.