PHWinfo banniere

Titres
PORTAIL ANNUAIRE ARTICLES COMPARATEUR HÉBERGEURS DEVIS FORUMS RÉDUCTEUR D'URL
Précédent   PHWinfo > Autres forums > Forum Programmation & Conception > comp.lang.c > Neatest way to get the end pointer?
S'inscrire FAQ Membres Recherche Messages du jour Marquer les forums comme lus
Neatest way to get the end pointer?

Réponse
 
LinkBack Outils de la discussion
Vieux 05/02/2008, 22h40   #1
Tomás Ó hÉilidhe
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Neatest way to get the end pointer?


I commonly use pointers to iterate thru an array. For example:

int my_array[X];

int *p = my_array;
int const *const pend = my_array + sizeof my_array/sizeof*my_array;

do *p++ = 42;
while (pend != p);

(Yes I realise the lack of spaces in the sizeof thing above is
disgusting, but I've gotten so sick of writing it out that I make it as
compact as possible)

I can't count how many times I use this construct in my code every day.
It's a right pain in the ass to always have to write out the long-winded
intialiser for pend, so I'm considering switching to initialising pend
as follows:

int const *const pend = *(&my_array+1);

1) my_array is an int[X]
2) &my_array is an int(*)[X]
3) &my_array+1 is the address of the non-existant array located after
the current one.
4) *(&my_array+ 1) decays to the address of the first element in the
non-existant array after the current one, which is also the "pend"
address for the array that actually exists.

It's a hell of a lot shorter to write, and also I think it's a little
less vulnerable to typos because you'll most likely get a type mismatch
if its written wrongly.

Anyway, just wondering what people think of the alternative. Saves me
that little rush of pissed-off-ness every time I've to write out the
tedious sizeof thing.

(Oh and by the way, I wouldn't use a macro such as ARRLEN(my_array)
because then I'd have to worry about including the necessary header
file... which is also the reason why I don't use NULL.)

--
Tomás Ó hÉilidhe
  Réponse avec citation
Vieux 05/02/2008, 23h24   #2
Army1987
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

Tomás Ó hÉilidhe wrote:

> I commonly use pointers to iterate thru an array. For example:
>
> int my_array[X];
>
> int *p = my_array;
> int const *const pend = my_array + sizeof my_array/sizeof*my_array;
>
> do *p++ = 42;
> while (pend != p);

Use a understandable macro for the array size, then you can have pend =
my_array + X.
(Also, I'd write it as `for (p = my_array; p < pend; p++) *p = 42;`. Or
even directly p < my_array + X, since a decent compiler should optimize
that, shouldn't it?)

--
Army1987 (Replace "NOSPAM" with "email")
  Réponse avec citation
Vieux 05/02/2008, 23h30   #3
vippstar@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

On Feb 6, 12:40 am, "Tomás Ó hÉilidhe" <t...@lavabit.com> wrote:
> I commonly use pointers to iterate thru an array. For example:
>
> int my_array[X];
>
> int *p = my_array;
> int const *const pend = my_array + sizeof my_array/sizeof*my_array;
>
> do *p++ = 42;
> while (pend != p);
>
> (Yes I realise the lack of spaces in the sizeof thing above is
> disgusting, but I've gotten so sick of writing it out that I make it as
> compact as possible)
>
> I can't count how many times I use this construct in my code every day.
> It's a right pain in the ass to always have to write out the long-winded
> intialiser for pend, so I'm considering switching to initialising pend
> as follows:
>
> int const *const pend = *(&my_array+1);
>
> 1) my_array is an int[X]
> 2) &my_array is an int(*)[X]
> 3) &my_array+1 is the address of the non-existant array located after
> the current one.

And you invoke undefined behavior.
> It's a hell of a lot shorter to write, and also I think it's a little
> less vulnerable to typos because you'll most likely get a type mismatch
> if its written wrongly.

You could have a macro, or not use pointers (use that X).
> Anyway, just wondering what people think of the alternative. Saves me
> that little rush of pissed-off-ness every time I've to write out the
> tedious sizeof thing.

But it invokes undefined behavior.
> (Oh and by the way, I wouldn't use a macro such as ARRLEN(my_array)
> because then I'd have to worry about including the necessary header
> file... which is also the reason why I don't use NULL.)

NULL is declared in many standard C header files, among them is
<stdio.h>
I cannot believe you don't use NULL because you worry about it not
being defined.
  Réponse avec citation
Vieux 06/02/2008, 00h08   #4
Keith Thompson
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

vippstar@gmail.com writes:
> On Feb 6, 12:40 am, "Tomás Ó hÉilidhe" <t...@lavabit.com> wrote:
>> I commonly use pointers to iterate thru an array. For example:
>>
>> int my_array[X];

[snip]
>> 1) my_array is an int[X]
>> 2) &my_array is an int(*)[X]
>> 3) &my_array+1 is the address of the non-existant array located after
>> the current one.

> And you invoke undefined behavior.

[...]

No, he doesn't. &my_array+1 is a valid address, just past the end of
my_array. Computing this address is ok; attempting to dereference it
would invoke UB.

--
Keith Thompson (The_Other_Keith) <kst-u@mib.org>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
  Réponse avec citation
Vieux 06/02/2008, 00h09   #5
William Ahern
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

vippstar@gmail.com wrote:
> On Feb 6, 12:40 am, "Tom?s ? h?ilidhe" <t...@lavabit.com> wrote:

<snip>
> > (Oh and by the way, I wouldn't use a macro such as ARRLEN(my_array)
> > because then I'd have to worry about including the necessary header
> > file... which is also the reason why I don't use NULL.)

> NULL is declared in many standard C header files, among them is
> <stdio.h>
> I cannot believe you don't use NULL because you worry about it not
> being defined.


I don't use NULL 'cause I don't know to what it's defined. Usually the NULL
macro expands to `0' or `(void *)0'. The former, typical on *BSD, needs to
be cast when used from a comma expression and the return type of your
function is a pointer, otherwise it might be evaluated as an int, which
might not be wide enough if (sizeof int != sizeof (void *)).

if (some_test_fails)
return (errno = ESOMETHING), (void *)NULL;

Likewise, you have to cast it when passing as a vararg.

execl("/bin/true", "true", (char *)NULL);

Usually I just use an unadorned `0' in my code. I do this in part because,
like the OP, I don't feel like including <stddef.h> or <stdio.h> or any
other header that I don't need. I comment my include statements to describe
what I'm [trying] to import; it got really old doing:

#include <stddef.h> /* NULL */

But, to each his own. I don't know very many people who do this. I'm okay
being alone

  Réponse avec citation
Vieux 06/02/2008, 00h14   #6
vippstar@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

On Feb 6, 2:08 am, Keith Thompson <ks...@mib.org> wrote:
> vipps...@gmail.com writes:
> > On Feb 6, 12:40 am, "Tomás Ó hÉilidhe" <t...@lavabit.com> wrote:
> >> I commonly use pointers to iterate thru an array. For example:

>
> >> int my_array[X];

> [snip]
> >> 1) my_array is an int[X]
> >> 2) &my_array is an int(*)[X]
> >> 3) &my_array+1 is the address of the non-existant array located after
> >> the current one.

> > And you invoke undefined behavior.

>
> [...]
>
> No, he doesn't. &my_array+1 is a valid address, just past the end of
> my_array. Computing this address is ok; attempting to dereference it
> would invoke UB.

I think that when the result of an expression is a non-valid pointer,
the behavior is undefined.
Correct me if I am wrong, but I have also seen comments in GNU code
like this:
--
/* ANSI C violation */
char * s = p - 1;
--
Where p points to the start of a string passed. 's' is never
dereferenced, only used for comparing purposes (while(p > s) or
something similar)
  Réponse avec citation
Vieux 06/02/2008, 00h22   #7
William Ahern
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

Tom?s ? h?ilidhe <toe@lavabit.com> wrote:
<snip>
> (Oh and by the way, I wouldn't use a macro such as ARRLEN(my_array)
> because then I'd have to worry about including the necessary header
> file... which is also the reason why I don't use NULL.)


I keep all my macros in a single file, e.g. `eval.h'. It has ARRAYLEN,
STRINGIFY, PASTE, XPASTE, PP_NARG (thanks Laurent!), most of *BSD's
<sys/param.h> (MIN, MAX, howmany, etc), and a few other gems I've concocted.

It's rare that I don't use at least one of these in a project. I've never
satisfactorily packaged my other tools, but this seems to work well (though
I'm still torn between `arraylen' and `ARRAYLEN').

  Réponse avec citation
Vieux 06/02/2008, 00h27   #8
vippstar@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

On Feb 6, 2:09 am, William Ahern <will...@wilbur.25thandClement.com>
wrote:
> vipps...@gmail.com wrote:
> > On Feb 6, 12:40 am, "Tom?s ? h?ilidhe" <t...@lavabit.com> wrote:

> <snip>
> > > (Oh and by the way, I wouldn't use a macro such as ARRLEN(my_array)
> > > because then I'd have to worry about including the necessary header
> > > file... which is also the reason why I don't use NULL.)

> > NULL is declared in many standard C header files, among them is
> > <stdio.h>
> > I cannot believe you don't use NULL because you worry about it not
> > being defined.

>
> I don't use NULL 'cause I don't know to what it's defined. Usually the NULL
> macro expands to `0' or `(void *)0'. The former, typical on *BSD, needs to
> be cast when used from a comma expression and the return type of your
> function is a pointer, otherwise it might be evaluated as an int, which
> might not be wide enough if (sizeof int != sizeof (void *)).

I don't think that can happend.
>
> if (some_test_fails)
> return (errno = ESOMETHING), (void *)NULL;

As i said, NULL does not need to be casted here.
You don't need the comma operator either. the expression '(x, y, z)'
evaluates to the type of z with value z.
> Likewise, you have to cast it when passing as a vararg.

You have to cast 0 to (char *)0 too.
> execl("/bin/true", "true", (char *)NULL);
>
> Usually I just use an unadorned `0' in my code. I do this in part because,
> like the OP, I don't feel like including <stddef.h> or <stdio.h> or any
> other header that I don't need.

That in my opinion is very bad practise for a project.
> I comment my include statements to describe
> what I'm [trying] to import; it got really old doing:
>
> #include <stddef.h> /* NULL */
>
> But, to each his own. I don't know very many people who do this. I'm okay
> being alone

Other programmers in your project might not be okay with that thought,
ask them first.
As for me, I wouldn't. Consider
--
char *p;
/* ... */
if(p == 0) /* did you really mean p == 0 or *p == 0 ? */
if(p == NULL) /* clearly ment p == NULL */
--
  Réponse avec citation
Vieux 06/02/2008, 00h32   #9
Walter Roberson
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

In article <8fan75-8gn.ln1@wilbur.25thandClement.com>,
William Ahern <william@wilbur.25thandClement.com> wrote:

>I don't use NULL 'cause I don't know to what it's defined. Usually the NULL
>macro expands to `0' or `(void *)0'. The former, typical on *BSD, needs to
>be cast when used from a comma expression and the return type of your
>function is a pointer, otherwise it might be evaluated as an int, which
>might not be wide enough if (sizeof int != sizeof (void *)).


> if (some_test_fails)
> return (errno = ESOMETHING), (void *)NULL;


No, if the return type of your function is a pointer then the
return value will be converted to the appropriate type as if by
assignment. Assigning a compile-time 0 to a pointer type is guaranteed
to result in a NULL pointer constant.
--
"Okay, buzzwords only. Two syllables, tops." -- Laurie Anderson
  Réponse avec citation
Vieux 06/02/2008, 00h34   #10
Peter Nilsson
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

vipps...@gmail.com wrote:
> Keith Thompson <ks...@mib.org> wrote:
> > vipps...@gmail.com writes:
> > > "Tomás Ó hÉilidhe" <t...@lavabit.com> wrote:
> > > > I commonly use pointers to iterate thru an array.
> > > > For example:
> > > > int my_array[X];

> > [snip]
> > > > 1) my_array is an int[X]
> > > > 2) &my_array is an int(*)[X]
> > > > 3) &my_array+1 is the address of the non-existant
> > > > array located after the current one.
> > >
> > > And you invoke undefined behavior.

> >
> > No, he doesn't. &my_array+1 is a valid address,


Though it requires a conversion back to int * if used
as a pointer 'index' compared against an int * iterator.

> > just past the end of my_array. Computing this address
> > is ok; attempting to dereference it would invoke UB.

>
> I think that when the result of an expression is a non-
> valid pointer, the behavior is undefined.


True, but one byte past the end of an array _is_ a valid
pointer.

> Correct me if I am wrong,


Keith already has.

> but I have also seen comments in GNU code like this:
> --
> /* ANSI C violation */
> char * s = p - 1;


One byte beyond is fine (though you can't dereference it),
but there are no special rights for one (or more) byte(s)
_before_.

> --
> Where p points to the start of a string passed. 's' is
> never dereferenced, ...


Doesn't matter. Implementations do not have to cope with
'one byte before'. An allocation can be made at the start
of a memory page. Merely calculating an address prior to
such a page may trap. In contrast, implementations _must_
cope with one byte beyond, which simply means that at
least one byte (but typically _at most_ one byte) is
reserved at the end of the memory space.

--
Peter
  Réponse avec citation
Vieux 06/02/2008, 00h41   #11
vippstar@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

On Feb 6, 2:34 am, Peter Nilsson <ai...@acay.com.au> wrote:
> vipps...@gmail.com wrote:
> > Keith Thompson <ks...@mib.org> wrote:
> > > vipps...@gmail.com writes:
> > > > "Tomás Ó hÉilidhe" <t...@lavabit.com> wrote:
> > > > > I commonly use pointers to iterate thru an array.
> > > > > For example:
> > > > > int my_array[X];
> > > [snip]
> > > > > 1) my_array is an int[X]
> > > > > 2) &my_array is an int(*)[X]
> > > > > 3) &my_array+1 is the address of the non-existant
> > > > > array located after the current one.

>
> > > > And you invoke undefined behavior.

>
> > > No, he doesn't. &my_array+1 is a valid address,

>
> Though it requires a conversion back to int * if used
> as a pointer 'index' compared against an int * iterator.
>
> > > just past the end of my_array. Computing this address
> > > is ok; attempting to dereference it would invoke UB.

>
> > I think that when the result of an expression is a non-
> > valid pointer, the behavior is undefined.

>
> True, but one byte past the end of an array _is_ a valid
> pointer.

Ah I see, thanks a lot.
> > Correct me if I am wrong,

>
> Keith already has.

Hehe, sorry mr Keith for doubting :-P.

However, as you said mr Nilsson, he (the OP) is then dereferencing it,
and invoking undefined behavior.
Also, the whole topic is moot.
if sizeof foo / sizeof *foo gives you the elements of foo, then foo
must be an array.
If it's an array it must be defined as 'foo[X]' or similar.
If X is a constant, foo + X is the last pointer (that is not valid to
dereference), if X is an object, it is still foo + X, however foo is
then a variable length array.
Therefore, there is no need for foo + sizeof foo / sizeof *foo.
  Réponse avec citation
Vieux 06/02/2008, 00h43   #12
A. Sinan Unur
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

vippstar@gmail.com wrote in
news:a6def63a-34ea-4248-a6d4-0c13e642e59b@1g2000hsl.googlegroups.com:

> On Feb 6, 2:08 am, Keith Thompson <ks...@mib.org> wrote:
>> vipps...@gmail.com writes:
>> > On Feb 6, 12:40 am, "Tomás Ó hÉilidhe" <t...@lavabit.com> wrote:
>> >> I commonly use pointers to iterate thru an array. For example:

>>
>> >> int my_array[X];

>> [snip]
>> >> 1) my_array is an int[X]
>> >> 2) &my_array is an int(*)[X]
>> >> 3) &my_array+1 is the address of the non-existant array located
>> >> after the current one.
>> > And you invoke undefined behavior.

>>
>> [...]
>>
>> No, he doesn't. &my_array+1 is a valid address, just past the end of
>> my_array. Computing this address is ok; attempting to dereference it
>> would invoke UB.

> I think that when the result of an expression is a non-valid pointer,
> the behavior is undefined.
> Correct me if I am wrong, but I have also seen comments in GNU code
> like this:
> --
> /* ANSI C violation */
> char * s = p - 1;
> --
> Where p points to the start of a string passed. 's' is never
> dereferenced, only used for comparing purposes (while(p > s) or
> something similar)


That is different, though. Pointing one past the end of the array is
valid whereas pointing oen before the start of the array is not.

http://www.open-std.org/jtc1/sc22/wg...docs/n1124.pdf

§6.5.6, page 83

Moreover, if the expression P points to the last
element of an array object, the expression (P)+1 points one past the
last element of the array object, and if the expression Q points one
past the last element of an array object, the expression (Q)-1 points to
the last element of the array object. If both the pointer operand and
the result point to elements of the same array object, or one past the
last element of the array object, the evaluation shall not produce an
overflow; otherwise, the behavior is undefined. If the result points one
past the last element of the array object, it shall not be used as the
operand of a unary * operator that is evaluated.


Sinan


--
A. Sinan Unur <1usa@llenroc.ude.invalid>
(remove .invalid and reverse each component for email address)
clpmisc guidelines: <URL:http://www.rehabitation.com/clpmisc.shtml>

  Réponse avec citation
Vieux 06/02/2008, 01h01   #13
Ben Bacarisse
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

vippstar@gmail.com writes:

> On Feb 6, 12:40 am, "Tomás Ó hÉilidhe" <t...@lavabit.com> wrote:
>> I commonly use pointers to iterate thru an array. For example:
>>
>> int my_array[X];
>>
>> int *p = my_array;
>> int const *const pend = my_array + sizeof my_array/sizeof*my_array;

<snip>
>> It's a right pain in the ass to always have to write out the long-winded
>> intialiser for pend, so I'm considering switching to initialising pend
>> as follows:
>>
>> int const *const pend = *(&my_array+1);
>>
>> 1) my_array is an int[X]
>> 2) &my_array is an int(*)[X]
>> 3) &my_array+1 is the address of the non-existant array located after
>> the current one.


> And you invoke undefined behavior.


Presumably not from the pointer arithmetic alone? Is it the deference
that you think causes UB?

That is my worry. One can construct a pointer "one past the end" of
any object, but * can't be applied "if it is evaluated" (6.5.6 p8). I
take that to refer to the rule that says that when & is applied to *,
neither are evaluated (6.5.3.2 p3).

I can't see anything wrong with:

int *pend = (void *)(&my_array + 1);

from a language point of view, but it is fragile in that it breaks
when the code moves to a function and my_array becomes a pointer.

Since "C has no array values" is one way of looking at the while
array/pointer relationship in C, one could argue that the * is not
evaluated in

int *pend = *(&my_array + 1);

Is the utility of this code sufficient to warrant a change to the
meaning of * (or definition of pointer arithmetic) to permit its use
when the "value" would be an array and would therefore be immediately
converted to a pointer?

--
Ben.
  Réponse avec citation
Vieux 06/02/2008, 01h01   #14
Richard Tobin
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

In article <foav6k$pfa$1@canopus.cc.umanitoba.ca>,
Walter Roberson <roberson@ibd.nrc-cnrc.gc.ca> wrote:

>> if (some_test_fails)
>> return (errno = ESOMETHING), (void *)NULL;


>No, if the return type of your function is a pointer then the
>return value will be converted to the appropriate type as if by
>assignment.


But the code is revolting anyway. I can see the temptation to
do something like

if(condition) a=1, b=2;

to avoid a block, but shoving an extra assignment into a return
statement is an unprovoked assault on readability.

-- Richard
--
:wq
  Réponse avec citation
Vieux 06/02/2008, 01h05   #15
Keith Thompson
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

vippstar@gmail.com writes:
> On Feb 6, 2:08 am, Keith Thompson <ks...@mib.org> wrote:
>> vipps...@gmail.com writes:
>> > On Feb 6, 12:40 am, "Tomás Ó hÉilidhe" <t...@lavabit.com> wrote:
>> >> I commonly use pointers to iterate thru an array. For example:

>>
>> >> int my_array[X];

>> [snip]
>> >> 1) my_array is an int[X]
>> >> 2) &my_array is an int(*)[X]
>> >> 3) &my_array+1 is the address of the non-existant array located after
>> >> the current one.
>> > And you invoke undefined behavior.

>>
>> [...]
>>
>> No, he doesn't. &my_array+1 is a valid address, just past the end of
>> my_array. Computing this address is ok; attempting to dereference it
>> would invoke UB.

> I think that when the result of an expression is a non-valid pointer,
> the behavior is undefined.
> Correct me if I am wrong, but I have also seen comments in GNU code
> like this:
> --
> /* ANSI C violation */
> char * s = p - 1;
> --
> Where p points to the start of a string passed. 's' is never
> dereferenced, only used for comparing purposes (while(p > s) or
> something similar)


Computing a pointer before the beginning of an array invokes UB;
computing a pointer just past the end of an array does not.

This is mentioned in passing in the answer to question 6.17 in the
comp.lang.c FAQ, <http://www.c-faq.com/> (can anyone find a more
explicit reference?).

The standard's rather long-winded explanation of this is in C99
6.5.6p8 (quoting from n1256; there are no change bars on this
paragraph):

When an expression that has integer type is added to or subtracted
from a pointer, the result has the type of the pointer operand. If
the pointer operand points to an element of an array object, and
the array is large enough, the result points to an element offset
from the original element such that the difference of the
subscripts of the resulting and original array elements equals the
integer expression. In other words, if the expression P points to
the i-th element of an array object, the expressions (P)+N
(equivalently, N+(P)) and (P)-N (where N has the value n) point
to, respectively, the i+n-th and in-th elements of the array
object, provided they exist. Moreover, if the expression P points
to the last element of an array object, the expression (P)+1
points one past the last element of the array object, and if the
expression Q points one past the last element of an array object,
the expression (Q)-1 points to the last element of the array
object. If both the pointer operand and the result point to
elements of the same array object, or one past the last element of
the array object, the evaluation shall not produce an overflow;
otherwise, the behavior is undefined. If the result points one
past the last element of the array object, it shall not be used as
the operand of a unary * operator that is evaluated.

--
Keith Thompson (The_Other_Keith) <kst-u@mib.org>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
  Réponse avec citation
Vieux 06/02/2008, 02h01   #16
Peter Nilsson
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

vipps...@gmail.com wrote:
> Peter Nilsson <ai...@acay.com.au> wrote:
> > ... one byte past the end of an array _is_ a valid
> > pointer.

>
> Hehe, sorry mr Keith for doubting :-P.
>
> However, as you said mr Nilsson, he (the OP) is then
> dereferencing it, and invoking undefined behavior.


I never said the OP dereferenced it. The actual code had
been snipped by that point. Here it is...

int *p = my_array;
int const *const pend = my_array + sizeof my_array/
sizeof*my_array;
do *p++ = 42;
while (pend != p);

At no stage is pend dereferenced; and the loop exits on
p == pend, so the address is not dereferenced by p
either.

--
Peter
  Réponse avec citation
Vieux 06/02/2008, 02h05   #17
vippstar@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

On Feb 6, 4:01 am, Peter Nilsson <ai...@acay.com.au> wrote:
> vipps...@gmail.com wrote:
> > Peter Nilsson <ai...@acay.com.au> wrote:
> > > ... one byte past the end of an array _is_ a valid
> > > pointer.

>
> > Hehe, sorry mr Keith for doubting :-P.

>
> > However, as you said mr Nilsson, he (the OP) is then
> > dereferencing it, and invoking undefined behavior.

>
> I never said the OP dereferenced it. The actual code had
> been snipped by that point. Here it is...
>
> int *p = my_array;
> int const *const pend = my_array + sizeof my_array/
> sizeof*my_array;
> do *p++ = 42;
> while (pend != p);
>
> At no stage is pend dereferenced; and the loop exits on
> p == pend, so the address is not dereferenced by p
> either.

Ah, I was a bit confused I guess.
However, OP _does_ dereference it. Not in that snipped, but in 4)
> 4) *(&my_array+ 1) decays to the address of the first element in the
> non-existant array after the current one, which is also the "pend"
> address for the array that actually exists.

  Réponse avec citation
Vieux 06/02/2008, 02h10   #18
vippstar@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

On Feb 6, 3:05 am, Keith Thompson <ks...@mib.org> wrote:
> vipps...@gmail.com writes:
> > On Feb 6, 2:08 am, Keith Thompson <ks...@mib.org> wrote:
> >> vipps...@gmail.com writes:
> >> > On Feb 6, 12:40 am, "Tomás Ó hÉilidhe" <t...@lavabit.com> wrote:
> >> >> I commonly use pointers to iterate thru an array. For example:

>
> >> >> int my_array[X];
> >> [snip]
> >> >> 1) my_array is an int[X]
> >> >> 2) &my_array is an int(*)[X]
> >> >> 3) &my_array+1 is the address of the non-existant array located after
> >> >> the current one.
> >> > And you invoke undefined behavior.

>
> >> [...]

>
> >> No, he doesn't. &my_array+1 is a valid address, just past the end of
> >> my_array. Computing this address is ok; attempting to dereference it
> >> would invoke UB.

> > I think that when the result of an expression is a non-valid pointer,
> > the behavior is undefined.
> > Correct me if I am wrong, but I have also seen comments in GNU code
> > like this:
> > --
> > /* ANSI C violation */
> > char * s = p - 1;
> > --
> > Where p points to the start of a string passed. 's' is never
> > dereferenced, only used for comparing purposes (while(p > s) or
> > something similar)

>
> Computing a pointer before the beginning of an array invokes UB;
> computing a pointer just past the end of an array does not.
>
> This is mentioned in passing in the answer to question 6.17 in the
> comp.lang.c FAQ, <http://www.c-faq.com/> (can anyone find a more
> explicit reference?).
>
> The standard's rather long-winded explanation of this is in C99
> 6.5.6p8 (quoting from n1256; there are no change bars on this
> paragraph):
>
> When an expression that has integer type is added to or subtracted
> from a pointer, the result has the type of the pointer operand. If
> the pointer operand points to an element of an array object, and
> the array is large enough, the result points to an element offset
> from the original element such that the difference of the
> subscripts of the resulting and original array elements equals the
> integer expression. In other words, if the expression P points to
> the i-th element of an array object, the expressions (P)+N
> (equivalently, N+(P)) and (P)-N (where N has the value n) point
> to, respectively, the i+n-th and in-th elements of the array
> object, provided they exist. Moreover, if the expression P points
> to the last element of an array object, the expression (P)+1
> points one past the last element of the array object, and if the
> expression Q points one past the last element of an array object,
> the expression (Q)-1 points to the last element of the array
> object. If both the pointer operand and the result point to
> elements of the same array object, or one past the last element of
> the array object, the evaluation shall not produce an overflow;
> otherwise, the behavior is undefined. If the result points one
> past the last element of the array object, it shall not be used as
> the operand of a unary * operator that is evaluated.

I have thought about this, and clearly the standard talks about
arrays.
If we have foo[N], then foo + N is a valid pointer that cannot be
dereferenced.
However, in foo = &bar; foo+1 is *not* a valid pointer because &bar is
a pointer, not an array.
Therefore, in OPs example, the expression cannot be computed and does
invoke undefined behavior.
Here is an example of what i am trying to say
--
int * foo;
int bar;
int baz[N];
foo = baz + N; /* valid */
foo = &bar + 1; /* invalid */
foo = &bar; /* valid */
foo++; /* invalid */
--
  Réponse avec citation
Vieux 06/02/2008, 02h15   #19
Peter Nilsson
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

vipps...@gmail.com wrote:
> Peter Nilsson <ai...@acay.com.au> wrote:
> > ...
> > int *p = my_array;
> > int const *const pend = my_array + sizeof my_array/
> > sizeof*my_array;
> > do *p++ = 42;
> > while (pend != p);

>
> > At no stage is pend dereferenced; and the loop exits on
> > p == pend, so the address is not dereferenced by p
> > either.

>
> Ah, I was a bit confused I guess.
> However, OP _does_ dereference it. Not in that snipped,
> but in 4)
>
> > 4) *(&my_array+ 1) decays to the address of the first
> > element in the non-existant array after the current one,
> > which is also the "pend" address for the array that
> > actually exists.


Again, it is not derefenced...

The type of my_array is int[]
The type of &my_array is int (*)[]
The type of &my_array + 1 is int (*)[]
The type of *(&my_array + 1) is int []

The last expression will decay to an int * when used in the
assignment to pend. At no stage is that pointer dereferenced.

--
Peter
  Réponse avec citation
Vieux 06/02/2008, 02h20   #20
vippstar@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

On Feb 6, 4:15 am, Peter Nilsson <ai...@acay.com.au> wrote:
> vipps...@gmail.com wrote:
> > Peter Nilsson <ai...@acay.com.au> wrote:
> > > ...
> > > int *p = my_array;
> > > int const *const pend = my_array + sizeof my_array/
> > > sizeof*my_array;
> > > do *p++ = 42;
> > > while (pend != p);

>
> > > At no stage is pend dereferenced; and the loop exits on
> > > p == pend, so the address is not dereferenced by p
> > > either.

>
> > Ah, I was a bit confused I guess.
> > However, OP _does_ dereference it. Not in that snipped,
> > but in 4)

>
> > > 4) *(&my_array+ 1) decays to the address of the first
> > > element in the non-existant array after the current one,
> > > which is also the "pend" address for the array that
> > > actually exists.

>
> Again, it is not derefenced...
>
> The type of my_array is int[]
> The type of &my_array is int (*)[]
> The type of &my_array + 1 is int (*)[]
> The type of *(&my_array + 1) is int []
>
> The last expression will decay to an int * when used in the
> assignment to pend. At no stage is that pointer dereferenced.

What i ment is that (&myarray + 1) is dereferenced, which would be
invalid, and if my reply to mr Thompson is correct, then even
computing &my_array+1 is invalid.
Remember; We are no longer talking about arrays but pointers, the
pointer-after-the-last-element rule does not apply.
  Réponse avec citation
Vieux 06/02/2008, 02h24   #21
Peter Nilsson
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

vipps...@gmail.com wrote:
> Keith Thompson <ks...@mib.org> wrote:
> > ...The standard's rather long-winded explanation of this
> > is in C99 6.5.6p8 ...

>
> I have thought about this, and clearly the standard talks
> about arrays. If we have foo[N], then foo + N is a valid
> pointer that cannot be dereferenced.
> However, in foo = &bar; foo+1 is *not* a valid pointer
> because &bar is a pointer, not an array.


The cited paragraph is specifically about adding an integer
to a pointer. Arrays decaying to pointers is in 6.3.2.1p3.

--
Peter
  Réponse avec citation
Vieux 06/02/2008, 02h27   #22
vippstar@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

On Feb 6, 4:24 am, Peter Nilsson <ai...@acay.com.au> wrote:
> vipps...@gmail.com wrote:
> > Keith Thompson <ks...@mib.org> wrote:
> > > ...The standard's rather long-winded explanation of this
> > > is in C99 6.5.6p8 ...

>
> > I have thought about this, and clearly the standard talks
> > about arrays. If we have foo[N], then foo + N is a valid
> > pointer that cannot be dereferenced.
> > However, in foo = &bar; foo+1 is *not* a valid pointer
> > because &bar is a pointer, not an array.

>
> The cited paragraph is specifically about adding an integer
> to a pointer. Arrays decaying to pointers is in 6.3.2.1p3.

I don't think you understand what I am trying to say.
--
char foo[N]; /* array of N length */
char c;
char *bar = foo + N; /* valid */
bar = &c + 1; /* invalid */
--
I understand the matter with arrays and the pointer over the last
element, but I believe that does not apply for pointers.
Furthermore, I think you don't understand arrays since you claimed
my_array to be int[] while it is int[X], and &my_array to be int (*)[]
while it is int (*)[X].
  Réponse avec citation
Vieux 06/02/2008, 02h29   #23
William Ahern
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Neatest way to get the end pointer?

vippstar@gmail.com wrote:
> On Feb 6, 2:09 am, William Ahern <will...@wilbur.25thandClement.com>
> wrote:

<snip>
> > I don't use NULL 'cause I don't know to what it's defined. Usually the NULL
> > macro expands to `0' or `(void *)0'. The former, typical on *BSD, needs to
> > be cast when used from a comma expression and the return type of your
> > function is a pointer, otherwise it might be evaluated as an int, which
> > might not be wide enough if (sizeof int != sizeof (void *)).

> I don't think that can happend.


It does on most of my machines.

> >
> > if (some_test_fails)
> > return (errno = ESOMETHING), (void *)NULL;

> As i said, NULL does not need to be casted here.
> You don't need the comma operator either. the expression '(x, y, z)'
> evaluates to the type of z with value z.


Indeed, exactly as 6.5.17 states. But, what is the type of an unadorned `0'?
(Note, as I mentioned earlier, on *BSD NULL is defined as simply `0'.) Is it
a pointer or an integer? In a comma expression, it's an integer, because
there's no other context to suggest otherwise. Why? I assume because the
language is too rigid. 6.5.17 must be satisified before 6.8.6.4(3)--which
specifies how expression types are coerced when used with return.

Try it in your compiler. GCC, for instance, exhibits this behavior.

cc test.c -o test
test.c: In function ‘foo’:
test.c:4: warning: return makes pointer from integer without a cast

This is one of the primary reasons I don't use NULL. Maybe its foolhardy
(likely, even), but if you truly grok how type coercion works in C, then the
visual syntactical benefit of using NULL loses much of its value. It's sort
of like seeing the red headed woman in a screen of falling green glyphs.
(Obligatory The Matrix reference.)

> > Likewise, you have to cast it when passing as a vararg.

> You have to cast 0 to (char *)0 too.
> > execl("/bin/true", "true", (char *)NULL);
> >
> > Usually I just use an unadorned `0' in my code. I do this in part because,
> > like the OP, I don't feel like including <stddef.h> or <stdio.h> or any
> > other header that I don't need.

> That in my opinion is very bad practise for a project.
> > I comment my include statements to describe
> > what I'm [trying] to import; it got really old doing:
> >
> > #include <stddef.h> /* NULL */
> >
> > But, to each his own. I don't know very many people who do this. I'm okay
> > being alone

> Other programmers in your project might not be okay with that thought,
> ask them first.
> As for me, I wouldn't. Consider
> --
> char *p;
> /* ... */
> if(p == 0) /* did you really mean p == 0 or *p == 0 ? */
> if(p == NULL) /* clearly ment p == NULL */


(1) Though you snipped the imaginary intermediate code, I strive to make all
of my function definitions fit within an 80x24 terminal window. So the
declaration is usually as easy to spot as it is here.

(2) How does that compare to?

if(!p) ...

Granted, I do indeed use the former, but my point is that very likely you
(or most other people) would find it less objectionable. But I don't expend
any effort to ease a programmer's cognitive load a