469,160 Members | 2,033 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,160 developers. It's quick & easy.

contradiction in TC++PL?

Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?

--
ES Kim
Jul 22 '05 #1
42 1867
Hi~
It's good to see you, you Korean right? me either..

Anyway,
"The result of taking the address of the element before the initial element is undefined and should be avoided." The author says, as I understand, it's ok with ++p after p--, which I think contradict the statement in the excerpt. What do you think?
Both clauses are right IMHO.
p-- actually returns the fist element's reference even though it decreaments
internal pointer..
It's because that's posfix..
So in this case, there in no way to access the element before the zeroth
element..

And then '++p' makes the pointer point to the zeroth element.. T v[200];
T* p = &v[0];
p--; // please note (my comment)
++p;
So then, the code above is not dangerous..

Is that your questions?
:)

"ES Kim" <no@spam.mail> wrote in message
news:cl**********@news1.kornet.net... Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think contradict the statement in the excerpt. What do you think?

--
ES Kim

Jul 22 '05 #2
"BekTek" <be****@gmail.com> wrote in message
news:h8_cd.2969$7d7.1176@trnddc04...
Hi~
It's good to see you, you Korean right? me either..
Yes, I'm a Korean. Nice to see you.

Anyway,
"The result of taking the address of the element before the initial

element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I

think
contradict the statement in the excerpt. What do you think?


Both clauses are right IMHO.
p-- actually returns the fist element's reference even though it decreaments
internal pointer..
It's because that's posfix..
So in this case, there in no way to access the element before the zeroth
element..

And then '++p' makes the pointer point to the zeroth element..


I'm not sure what you mean by 'internal pointer'.
There's no difference between postfix and prefix form in this context.
The expression p-- is evaluated as a pointer to the initial element,
but it also has a side effect, which makes p point to the address before
the initial element.

--
ES Kim
Jul 22 '05 #3
* ES Kim:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?


According to Google it's not in the errata list.

Executing those statements in sequence is definitely Undefined Behavior,
and in particular the increment can not "fix" the earlier invoked UB.

Mail Bjarne and get the $30 prize money (or whatever the amount is... ;-)).

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #4
ES Kim wrote:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?

p--; produces undefined behaviour since it points to an invalid element.
This is allowed only for one past the end element of a sequence.

++p; reincrements the pointer and points to the first element. In this
place, p is again pointing to a valid element and in this state it is
well defined.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #5
Alf P. Steinbach wrote:
* ES Kim:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?

According to Google it's not in the errata list.

Executing those statements in sequence is definitely Undefined Behavior,
and in particular the increment can not "fix" the earlier invoked UB.

Mail Bjarne and get the $30 prize money (or whatever the amount is... ;-)).

Actually there is not any book error, since it is stated that undefined
behaviour is invoked.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #6
* Ioannis Vranos:
ES Kim wrote:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?

p--; produces undefined behaviour since it points to an invalid element.
This is allowed only for one past the end element of a sequence.

++p; reincrements the pointer and points to the first element. In this
place, p is again pointing to a valid element and in this state it is
well defined.


That is incorrect.

The result of the decrement is UB.

The result of incrementing that result is UB, not a "reincrement".

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #7
* Ioannis Vranos:
Alf P. Steinbach wrote:
* ES Kim:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?

According to Google it's not in the errata list.

Executing those statements in sequence is definitely Undefined Behavior,
and in particular the increment can not "fix" the earlier invoked UB.

Mail Bjarne and get the $30 prize money (or whatever the amount is... ;-)).

Actually there is not any book error, since it is stated that undefined
behaviour is invoked.


I'm assuming the "ok" comment is from the book.

If so then this is an error.

See reply to your other response.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #8
"Ioannis Vranos" <iv*@guesswh.at.grad.com> wrote in message
news:1098154188.513463@athnrd02...
ES Kim wrote:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I think
contradict the statement in the excerpt. What do you think?

p--; produces undefined behaviour since it points to an invalid element.
This is allowed only for one past the end element of a sequence.

++p; reincrements the pointer and points to the first element. In this
place, p is again pointing to a valid element and in this state it is
well defined.


There's no guarantee that "p is again pointing to a valid element".
Even one UB will make every following well-defined statements undefined.

--
ES Kim
Jul 22 '05 #9
ES Kim wrote:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial element
is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--,
which I think contradict the statement in the excerpt. What do you think?


Correct. It's a bad example. A better example might be:

void f1(T a) {
T v[200];
T* p = &v[0];
*p = a; // ok
p--; // undefined but works everywhere
*p = a; // run-time error: 'p' out of range
++p; // still undefined but works everywhere
*p = a; // undefined but works everywhere
}
Jul 22 '05 #10
Alf P. Steinbach wrote:
That is incorrect.

The result of the decrement is UB.

The result of incrementing that result is UB, not a "reincrement".


Evidently, Alf is unclear on the concept of undefined behavior.

Alf,

Claiming the result of the increment is not "reincrement"
implies that the behavior *is* defined.
The standard certainly allows the implementation
to define the behavior of the increment (in this case)
to be "reincrement" and every standard compliant implementation
currently in existence defines it this way.
Jul 22 '05 #11
"E. Robert Tisdale" <E.**************@jpl.nasa.gov> wrote in message
news:cl**********@nntp1.jpl.nasa.gov...
Alf P. Steinbach wrote:
That is incorrect.

The result of the decrement is UB.

The result of incrementing that result is UB, not a "reincrement".


Evidently, Alf is unclear on the concept of undefined behavior.

Alf,

Claiming the result of the increment is not "reincrement"
implies that the behavior *is* defined.
The standard certainly allows the implementation
to define the behavior of the increment (in this case)
to be "reincrement" and every standard compliant implementation
currently in existence defines it this way.


Given the context, I think Alf's comment is correct. While UB really means
that anything can happen, including "reincrement", the original assertion,
from my understanding, was that the behavior was always defined to be
"reincrement" and only "reincrement", which is not strictly true. But, as
Bill Clinton would say, that all depends upon what we mean by "is". ;-)

You're right, though, it could always work on a given implementation, and it
does work on most implementations (or virtually all implementations, as you
have maintained in the past). In the eyes of the standard, however, it's
just UB.

--
David Hilsee
Jul 22 '05 #12
David Hilsee wrote:
Given the context, I think Alf's comment is correct. While UB really means
that anything can happen, including "reincrement", the original assertion,
from my understanding, was that the behavior was always defined to be
"reincrement" and only "reincrement", which is not strictly true. But, as
Bill Clinton would say, that all depends upon what we mean by "is". ;-)

You're right, though, it could always work on a given implementation, and it
does work on most implementations (or virtually all implementations, as you
have maintained in the past). In the eyes of the standard, however, it's
just UB.

Pointing to an invalid element, is undefined behaviour.
In reality, when the pointer gets reincremented, it does point to a
valid element and not somewhere else.
However "legally" speaking, the undefined behaviour invoked can even
change the value of the pointer itself and in such a case reincrementing
it will not point to the same object.
In general, when UB is invoked, the rest of the code is UB too.
So I have to agree with Alf in the end. :-)

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #13
ES Kim wrote:
There's no guarantee that "p is again pointing to a valid element".
Even one UB will make every following well-defined statements undefined.

Yes, you are right.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #14
ES Kim posted:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial
element is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I
think contradict the statement in the excerpt. What do you think?


Well consider this:

If you use reinterpret_cast to convert a pointer value to an unsigned
integral value (assuming the integral type is large enough to hold the
value) and then reconvert it back, then you're left with a valid pointer.

So while the following may be invalid:

int jack[6];

int* p = jack;

--p; //There may be overflow, for instance if p == 0
I'd advocate that the following *is* legal:
int jack[6];

int* p = jack;

unsigned long address = reinterpret_cast<unsigned long const>(p);

--address;
//We don't have to check for overflow because it's
//guaranteed not to occur with unsigned integrals.

p = reinterpret_cast<int* const>(address);

//Now 'p' points to one before the start of the array.

++address;

p = reinterpret_cast<int* const>(address);

//And now we're back to the first element

In short, I would say that it's safe to increment or decrement a pointer
however you see fit, but just watch out for overflow! For instance:

int blah[50];

int* p = blah;

--p; //You can't be sure there's no overflow!
To simply say "it's UB to do this" even though there's a perfect logic
behind it to illustrate what's going on, is simply being formal and
pedantic.
-JKop
Jul 22 '05 #15
Alf P. Steinbach wrote:

According to Google it's not in the errata list.

Executing those statements in sequence is definitely Undefined Behavior,
and in particular the increment can not "fix" the earlier invoked UB.

Mail Bjarne and get the $30 prize money (or whatever the amount is...
;-)).

There are several examples like this. It would be a mistake to read the
textbook examples containing such UB as collectively well defined. They
are merely pedagogical devices containing inconsistencies for the sake of
brevity.

--
"If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true." - Bertrand
Russell

Jul 22 '05 #16
JKop wrote:
Well consider this:

If you use reinterpret_cast to convert a pointer value to an unsigned
integral value (assuming the integral type is large enough to hold the
value) and then reconvert it back, then you're left with a valid pointer.

Where did you read that?
From the C90 draft that I have:

"Conversions that involve pointers (other than as permitted by the
constraints of $3.3.16.1) shall be specified by means of an explicit
cast; they have implementation-defined aspects: A pointer may be
converted to an integral type. The size of integer required and the
result are implementation-defined. If the space provided is not long
enough, the behavior is undefined. An arbitrary integer may be
converted to a pointer. The result is implementation-defined."

So while the following may be invalid:

int jack[6];

int* p = jack;

--p; //There may be overflow, for instance if p == 0
The above doesn't make sense.
I'd advocate that the following *is* legal:
int jack[6];

int* p = jack;

unsigned long address = reinterpret_cast<unsigned long const>(p);

--address;
//We don't have to check for overflow because it's
//guaranteed not to occur with unsigned integrals.

p = reinterpret_cast<int* const>(address);

//Now 'p' points to one before the start of the array.

++address;

p = reinterpret_cast<int* const>(address);

//And now we're back to the first element

The above is non-sense. Consider this:
#include <iostream>

int main()
{
int array[10]={1,2,3,4,5,6,7,8,9,10};

char *p=reinterpret_cast<char *>(&array[0]);

// Reads the first byte of every int in the array
for(unsigned i=0; i<10; ++i)
std::cout<<static_cast<int>(p[i*sizeof(*array)]);
}


Or in other words p[5*sizeof(int)] refers to the 5th element of the int
array as opposed to p[5] which would read the 5th element of a char array.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #17
From the C90 draft that I have:


Wrong language dude.
Anyway, regarding C++:
5.2.10

5 A value of integral type or enumeration type can be explicitly converted
to a pointer.64) A pointer converted
to an integer of sufficient size (if any such exists on the implementation)
and back to the same pointer type
will have its original value; mappings between pointers and integers are
otherwise implementation-defined.
-JKop
Jul 22 '05 #18
In message <cl**********@nntp1.jpl.nasa.gov>, E. Robert Tisdale
<E.**************@jpl.nasa.gov> writes
Alf P. Steinbach wrote:
That is incorrect.
The result of the decrement is UB.
The result of incrementing that result is UB, not a "reincrement".


Evidently, Alf is unclear on the concept of undefined behavior.

Alf,

Claiming the result of the increment is not "reincrement"
implies that the behavior *is* defined.
The standard certainly allows the implementation
to define the behavior of the increment (in this case)
to be "reincrement" and every standard compliant implementation
currently in existence defines it this way.


Do you have documentation for this stupendously sweeping claim?

Or are you merely suggesting that there are no standard-compliant
implementations?

--
Richard Herring
Jul 22 '05 #19
"JKop" <NU**@NULL.NULL> wrote in message
news:1M*******************@news.indigo.ie...

If you use reinterpret_cast to convert a pointer value to an unsigned
integral value (assuming the integral type is large enough to hold the
value) and then reconvert it back, then you're left with a valid pointer.

So while the following may be invalid:

int jack[6];

int* p = jack;

--p; //There may be overflow, for instance if p == 0
That is, if p is null pointer?
Surely you're joking, Mr. JKop. ;-)
I'd advocate that the following *is* legal:
[your logic snipped]
To simply say "it's UB to do this" even though there's a perfect logic
behind it to illustrate what's going on, is simply being formal and
pedantic.


Each implementation has its own "perfect" logic. The problem is, there are
some disagreements among them, and what we call UB is a kind of the
disagreement.
I admit I've never seen any implementation that causes trouble with the
original code, but that does not mean it will be ok all the time in the future.

--
ES Kim
Jul 22 '05 #20
ES Kim posted:
"JKop" <NU**@NULL.NULL> wrote in message
news:1M*******************@news.indigo.ie...

If you use reinterpret_cast to convert a pointer value to an unsigned
integral value (assuming the integral type is large enough to hold the
value) and then reconvert it back, then you're left with a valid
pointer.

So while the following may be invalid:

int jack[6];

int* p = jack;

--p; //There may be overflow, for instance if p == 0


That is, if p is null pointer?
Surely you're joking, Mr. JKop. ;-)

The value for a null pointer is implementation defined.

Just because when you write:

int* k = 0;

it sets it to a null pointer, doesn't mean that the null pointer value is in
actual fact 0. Consider the following to be the definition of a pointer:

class *
{
public:
*& operator=(int value)
{
if ( !value )
{
//Set to null pointer value
}
else

...

}
};
-JKop
Jul 22 '05 #21
JKop wrote:
From the C90 draft that I have:

Wrong language dude.

Actually I had searched in C++98 unsuccessfully, that's why I fell back
to C90 (which is a subset of C++98 except of the cases where something
else is provided).
Anyway, regarding C++:
5.2.10

5 A value of integral type or enumeration type can be explicitly converted
to a pointer.64) A pointer converted
to an integer of sufficient size (if any such exists on the implementation)
and back to the same pointer type
will have its original value; mappings between pointers and integers are
otherwise implementation-defined.

The above means that you can't assign a pointer value to an unsigned,
increment the unsigned and reassign the result back to the pointer and
expect well-defined behaviour.
You can only assign a pointer to an integer than can store it, and
reassign that back.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #22
JKop wrote:
int jack[6];

int* p = jack;

--p; //There may be overflow, for instance if p == 0


That is, if p is null pointer?
Surely you're joking, Mr. JKop. ;-)


The value for a null pointer is implementation defined.

Just because when you write:

int* k = 0;

it sets it to a null pointer, doesn't mean that the null pointer value is in
actual fact 0. Consider the following to be the definition of a pointer:

class *
{
public:
*& operator=(int value)
{
if ( !value )
{
//Set to null pointer value
}
else

...

}
};


A null pointer never points to a valid object.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #23
On Tue, 19 Oct 2004 07:55:41 GMT, JKop <NU**@NULL.NULL> wrote:
ES Kim posted:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

And here's an excerpt from p92:

"The result of taking the address of the element before the initial
element is undefined and should be avoided."

The author says, as I understand, it's ok with ++p after p--, which I
think contradict the statement in the excerpt. What do you think?
Well consider this:

If you use reinterpret_cast to convert a pointer value to an unsigned
integral value (assuming the integral type is large enough to hold the
value) and then reconvert it back, then you're left with a valid pointer.

So while the following may be invalid:

int jack[6];

int* p = jack;

--p; //There may be overflow, for instance if p == 0


How would p == 0? p can't be a null pointer since it points to jack
(!)

The reason that it is undefined is that it is illegal to form a
pointer that doesn't point within an object, or one past the end of an
object, or to "0". A debugging implementation might generate code to
enforce this.
I'd advocate that the following *is* legal:
int jack[6];

int* p = jack;

unsigned long address = reinterpret_cast<unsigned long const>(p);

--address;
//We don't have to check for overflow because it's
//guaranteed not to occur with unsigned integrals.

p = reinterpret_cast<int* const>(address);

//Now 'p' points to one before the start of the array.
But that makes p an invalid pointer value, so the above cast and
assignment have UB.
In short, I would say that it's safe to increment or decrement a pointer
however you see fit, but just watch out for overflow!
Overflow isn't really the issue, rather it is a more fundamental one
that pointer rvalues must point within an object (or one past the
end). This is partly to allow for an implementation that has special
pointer registers where pointer values are checked for validity
whenever they are loaded into the register.
To simply say "it's UB to do this" even though there's a perfect logic
behind it to illustrate what's going on, is simply being formal and
pedantic.


I don't think that talking about overflow sheds any light on the
topic; overflow is not necessarily the underlying problem.

Tom
Jul 22 '05 #24


So what do you think of the following, does it exhibit UB in your opinion?:

int main()
{
long* p_blah = reinterpret_cast<long* const>(297239);
}
In my own opinion, it does *not* exhibit UB.
-JKop
Jul 22 '05 #25
On Tue, 19 Oct 2004 11:38:11 GMT, JKop <NU**@NULL.NULL> wrote:


So what do you think of the following, does it exhibit UB in your opinion?:

int main()
{
long* p_blah = reinterpret_cast<long* const>(297239);
}
In my own opinion, it does *not* exhibit UB.


Actually, I think my statement of UB might have been a bit strong -
it's implementation defined behaviour (which may of course be defined
to do anything). For example, on DOS, such expressions can be used to
access video memory IIRC. On other platforms they might cause a crash:

"A value of integral type or enumeration type can be explicitly
converted to a pointer. A pointer converted
to an integer of sufficient size (if any such exists on the
implementation) and back to the same pointer type
will have its original value; ___mappings between pointers and
integers are otherwise implementation-defined___." (my emphasis)

So it's up to the implementation what it does when casting 297239 to a
pointer. Casting the --val back to a pointer (in the previous example)
is similarly implementation defined.

Tom
Jul 22 '05 #26
JKop wrote:
So what do you think of the following, does it exhibit UB in your opinion?:

int main()
{
long* p_blah = reinterpret_cast<long* const>(297239);
}
In my own opinion, it does *not* exhibit UB.

It invokes implementation defined behaviour.

However
long x;

long *p=&x;

p--;

is undefined behaviour.

Some explanation on this: A pointer type is not required to be
implemented as an integer type.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #27
Ioannis Vranos posted:
JKop wrote:
So what do you think of the following, does it exhibit UB in your
opinion?:

int main()
{
long* p_blah = reinterpret_cast<long* const>(297239); }
In my own opinion, it does *not* exhibit UB.

It invokes implementation defined behaviour.


For the love of Christ it does nothing!
-JKop
Jul 22 '05 #28
JKop wrote:
int main()
{
long* p_blah = reinterpret_cast<long* const>(297239); }
In my own opinion, it does *not* exhibit UB.

It invokes implementation defined behaviour.



For the love of Christ it does nothing!


It invokes implementation defined behaviour. This style is used in many
systems to access specific portions of memory that provide specific
functionality.
The assignment is implementation defined, with no side effects. However
if the assignment is not valid, any attempt to dereference the pointer
invokes undefined behaviour.
This is all "legal" stuff. The standard tries to provide as much
guarantees as possible, portably.
So for example, this assignment being implementation defined guarantees
that your program will not crash or something by this assignment alone.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #29
In message <7O*******************@news.indigo.ie>, JKop <NU**@NULL.NULL>
writes
Ioannis Vranos posted:
JKop wrote:
So what do you think of the following, does it exhibit UB in your
opinion?:

int main()
{
long* p_blah = reinterpret_cast<long* const>(297239); }

In my own opinion, it does *not* exhibit UB.


It invokes implementation defined behaviour.


For the love of Christ it does nothing!

Hardly "nothing". It initialises a pointer with a bit pattern that may
not represent a valid hardware address. On some platforms which have
dedicated "address registers" and check their validity, that may be
sufficient to generate some kind of hardware exception.

--
Richard Herring
Jul 22 '05 #30
Hardly "nothing". It initialises a pointer with a bit pattern that may
not represent a valid hardware address. On some platforms which have
dedicated "address registers" and check their validity, that may be
sufficient to generate some kind of hardware exception.

...puke-a-licious
Are you sure they're allowed do that?!
To those machines I barketh:

union
{
long a;
int* p_b;
} poo;
Now check the God damn address, I ddaarree ya!
-JKop
Jul 22 '05 #31
In message <uz*******************@news.indigo.ie>, JKop <NU**@NULL.NULL>
writes
Hardly "nothing". It initialises a pointer with a bit pattern that may
not represent a valid hardware address. On some platforms which have
dedicated "address registers" and check their validity, that may be
sufficient to generate some kind of hardware exception.

...puke-a-licious
Are you sure they're allowed do that?!


Why do you think the standard's so careful about what you can and can't
do with reinterpret_cast and pointers?
To those machines I barketh:

union
{
long a;
int* p_b;
} poo;
Now check the God damn address, I ddaarree ya!


Compilers know unions are dangerous... it won't load an address register
until you use p_b. It's up to you the programmer to make sure its
contents are valid at that time.

--
Richard Herring
Jul 22 '05 #32
JKop schrieb:
Hardly "nothing". It initialises a pointer with a bit pattern that may
not represent a valid hardware address. On some platforms which have
dedicated "address registers" and check their validity, that may be
sufficient to generate some kind of hardware exception.
...puke-a-licious


Have you considered that this isn't something bad, but can help enhance
program safety as it causes a well-defined exception instead of Funny
Behaviour (tm) when an invalid pointer creeps in?
Are you sure they're allowed do that?!
Absolutely. See 5.2.10/5:

"[...] A pointer converted to an integer of sufficient size
(if any such exists on the implementation) and back to the
same pointer will have its original value; mappings between
pointers and integers are otherwise implementation defined."

As long as the defined case (back-and-forth conversion) doesn't result
in a hardware exception, the behiviour is fully compliant as I read the
above.
To those machines I barketh:

union
{
long a;
int* p_b;
} poo;
Now check the God damn address, I ddaarree ya!


Check 9.5/1 about unions. You must not inspect, i.e. read, poo.p_b
after assigning to poo.a, but before assigning to poo.p_b, I don't see
POD structs with an initial sequence in poo...

Regards,
Malte
Jul 22 '05 #33
Ron Natalie <ro*@sensor.com> wrote in news:41754189$0$28315
$9*******@news.newshosting.com:
ES Kim wrote:
Here's a code fragment from TC++PL Special Edition, p291:

void f1(T a)
{
T v[200];
T* p = &v[0];
p--; // please note (my comment)
*p = a; // oops: 'p' out of range, uncaught
++p;
*p = a; // ok
}

I don't have Page 92, but once you've done the p--, the rest
of the program is undefined. There is NO guarantee that you
can adjust the pointer outside the bounds of the array (including
one past the end) and be able to do anything with it furhter.


Yes you can. It is perfectly legal to form a pointer to the "one-past-the-
end" position of an array. You can then decrement it back into the range
of the array, and that's still legal. What you cannot do is dereference
that pointer (while it is one-past-the-end, or &v[200]). What is true is
that you may not form the pointer "one-before-the-beginning" position (&v[-
1]), or the "*two*-past-the-end" pointer (&v[201]). The program above
attempts to form the "one-before-the-beginning" pointer, and thus invokes
undefined behaviour. Even worse is that on the next line it ends up
dereferencing that pointer....
Jul 22 '05 #34
Andre Kostur wrote:

Yes you can. It is perfectly legal to form a pointer to the "one-past-the-
end" position of an array. You can then decrement it back into the range
of the array, and that's still legal.


That's what I meant the "including one past the end" binds to the "bounds
of the array" not "outside the bounds of the array." Sorry, for not being clear./
Jul 22 '05 #35
Yes you can. It is perfectly legal to form a pointer to the
"one-past-the- end" position of an array.

Why so?
Let's say a certain system has 32-Bit pointers.
A 32-Bit storage can have 4,294,967,296 unique different values.
If we take away the null pointer, we're left with 4,294,967,295 different
values. Let's say for example that a certain system isn't shit in that it
doesn't waste memory. Let's say that we have an array:
int blah[5];
And its elements' addresses are:

&blah[1] == 4,294,967,291
&blah[2] == 4,294,967,292
&blah[3] == 4,294,967,293
&blah[4] == 4,294,967,294
&blah[5] == 4,294,967,295

int* p = &blah[5];

++p;
What then?
What's the logic behind being able to have a pointer to one past the end of
an array?
-JKop
Jul 22 '05 #36
&blah[1] == 4,294,967,291
&blah[2] == 4,294,967,292
&blah[3] == 4,294,967,293
&blah[4] == 4,294,967,294
&blah[5] == 4,294,967,295

int* p = &blah[5];

++p;

Should've written:

&blah[0] == 4,294,967,291
&blah[1] == 4,294,967,292
&blah[2] == 4,294,967,293
&blah[3] == 4,294,967,294
&blah[4] == 4,294,967,295

int* p = &blah[4];

++p;
Jul 22 '05 #37
JKop wrote:


If we take away the null pointer, we're left with 4,294,967,295 different
values. Let's say for example that a certain system isn't shit in that it
doesn't waste memory. Let's say that we have an array:


The implementation is free to use the last char* value you propose as
long as it makes the pointer math work. The issue is that the "one
past the end" value needs to be testable to make paradigms like

for(ptr = array[0]; ptr != &array[SIZE]; ++ptr) { ..

work. &array[SIZE] isn't part of the array, but it has to
participate in the pointer math.

It's not "wasting memory", the trivial idea (not using 0 or 2**N - 1)
is just wasting a few bytes of address space.

Jul 22 '05 #38

"JKop" <NU**@NULL.NULL> wrote in message
news:zp*******************@news.indigo.ie...
Have you considered that this isn't something bad, but can help enhance
program safety as it causes a well-defined exception instead of Funny
Behaviour (tm) when an invalid pointer creeps in?

When I have the likes of:
struct Blah
{
int a;
double b;
int* p_k;

float** p_p_f;
};
I should be able to set it to whatever the hell I please!

I think the point here is that we're now talking about "implementation
defined" behavior. Since you're not (yet) dereferencing the pointer(s),
there's no "undefined behavior" going on. But it's certainly possible that
you could be compiling for a platform that implements addresses in adress
registers, isn't it? In that case, wouldn't it behoove (I love that word
:-)) them to disallow somehow any assignment of an address which is not
valid?

Implementation defined behavior is simply where the Standard allows a
compiler to take the actions it needs to take under the given conditions,
rather than specify them explicitly. Assuming that this actually *is*
implementation-defined (I really don't know for sure, not having the
standard handy), it just means that you'd have to check your own compiler(s)
before attempting that kind of action. And I'm sure you'll agree that
explictly setting a pointer value to be anything other than NULL, or the
address of an existing object (or its member), is pretty senseless, eh?

I'd like some clarity on the issue. Will the following behave identically
on
all implementations, ie. will it output "I'm not a shit implementation!"
on
all platforms?:
int main()
{
bool* p_boolean = reinterpret_cast<bool* const>(92729);

std::cout << "I'm not a shit implementation!";
}


I have absolutely NO idea if it's actually done that way on any specific
platform, but there's likely to be far more platforms out there than I care
to list, let alone test on, dontcha think? :-)

-Howard
Jul 22 '05 #39
for(ptr = array[0]; ptr != &array[SIZE]; ++ptr) { ..

Could you please elaborate on that? Here's my feeble attempt:

#include <cstddef>

int main()
{
std::size_t SIZE = 6;

int array[SIZE];

for(int* ptr = array[0]; ptr != &array[SIZE]; ++ptr)
{
//But we have a type mismatch just above
}

}
It's not "wasting memory", the trivial idea (not using 0 or 2**N - 1)
is just wasting a few bytes of address space.

Let's say we've 64MB of RAM. 63MB of RAM are being used. We want to create
an object of a structure, where sizeof(MyStruct) == .75MB

Not enough memory.
-JKop

Jul 22 '05 #40
JKop wrote:
std::size_t SIZE = 6;

int array[SIZE];

for(int* ptr = array[0]; ptr != &array[SIZE]; ++ptr)
The init clause should be int *ptr = array; or int* ptr = &array[0];
My fat fingers (and outlook makes a lousy syntax checker).

By the way, the array size needs to be a constant experssion above.

Let's say we've 64MB of RAM. 63MB of RAM are being used. We want to create
an object of a structure, where sizeof(MyStruct) == .75MB

Not enough memory.

It's got nothing to do with RAM. It has to do with address space.
Go read a book on computers. There doesn't need to be any memory
(virtual or otherwise) backing up the "inaccessible" values.
Jul 22 '05 #41
JKop wrote:
What the hell ever happened to the whole concept of POD?

Plain Ol' Data

PLAIN OL' DATA!
When I have the likes of:
struct Blah
{
int a;
double b;
int* p_k;

float** p_p_f;
};
I should be able to set it to whatever the hell I please!
PODs aren't types of the 60s era, but of the C90 era.
Checking a pointer to see if it has a valid value (and perhaps throwing an
exception if not) is complete and utter total bullshit. It's inefficient
too. If I wanted such a mechanism, I'd explicitly ask for it:

int* k = ...

CheckPointer(k);
I'd like some clarity on the issue. Will the following behave identically on
all implementations, ie. will it output "I'm not a shit implementation!" on
all platforms?:
int main()
{
bool* p_boolean = reinterpret_cast<bool* const>(92729);

std::cout << "I'm not a **pepper** implementation!";
}


The above never causes side effects. Assignment of an integer to a
pointer type results in implementation defined behaviour, as far as you
do not dereference it.
"1.3.5 implementation-defined behavior

behavior, for a well-formed program construct and correct data, that
depends on the implementation and that each implementation shall document."

This means that you will never get unexpected effects for that.

On the other hand, pointing with a pointer to an invalid object (usually
with pointer arithmetic), results in undefined behaviour.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #42
JKop wrote:
What's the logic behind being able to have a pointer to one past the end of
an array?

Algorithms. One reason is in loops using a pointer or iterator with p++
incrementing, which at the end of the sequence points one past the last
element, and thus it has to be guaranteed that it is safe to do so.

--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #43

This discussion thread is closed

Replies have been disabled for this discussion.

By using this site, you agree to our Privacy Policy and Terms of Use.