Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   Arithmetic will null pointer (http://www.velocityreviews.com/forums/t725760-arithmetic-will-null-pointer.html)

 Urs Thuermann 06-16-2010 01:08 PM

Arithmetic will null pointer

I have again a question that I don't find a definitve answer for in my
draft copy of ISO 9899-99: Is it allowed to add an integer to a null
pointer and what will be the result?

See the following short example:

char *a = 0, *b = 0, *p, *q;
void f(void)
{
p = a + 0;
q = a + 10;
}

I only could find constraints for pointers that point to an object in

Constraints

[#2] For addition, either both operands shall have
arithmetic type, or one operand shall be a pointer to an
object type and the other shall have integer type.
(Incrementing is equivalent to adding 1.)

So the pointer must have object type (as opposed to void*), but does
not need to point to an object. Right? Then (char*)0 would be ok.

[#7] For the purposes of these operators, a pointer to a
nonarray object behaves the same as a pointer to the first
element of an array of length one with the type of the
object as its element type.

[#8] 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, ...

The null pointer is neither a pointer to a nonarray object nor a
pointer to an array element. So [#8] only says that (char*)0 + 1 is
of type (char*), but the rest is irrelvant.

So is that addition allowed? And is there a guarantee, that

(char*)0 + 0 == (char*)0

and

(char*)0 + 1 != (char*)0

It is clear that allmost all implementations will do so but can one
rely on this? This question turned up to me when I was writing a
short code snippet, similar to this:

char *s = 0, *old;
size_t size = 0, len = 0, n;

for (...) {
do {
n = snprintf(s + len, size - len, fmt, ...);
if (n >= size - len) {
old = s;
size += 1024;
s = realloc(s, size);
if (!s) {
goto error;
}
}
} while (s != old);
len += n;
}

The term s + len will be null pointer plus 0 in the first iteration.
(BTW, snprint(NULL, 0, ...) is allowed by ISO C, no problem here).

urs

 Urs Thuermann 06-16-2010 07:42 PM

Re: Arithmetic will null pointer

Richard Heathfield <rjh@see.sig.invalid> writes:

> The compiler is not required to diagnose such an addition, but the
> behaviour is undefined. See paragraph 8 of the section you quoted

I don't see where this paragraph says that such an addition yields
undefined behavior. That paragraph starts as follows:

[#8] When an expression that has integer type is added to or
subtracted from a pointer, the result has the type of the
pointer operand.

This only specifies that the type of (char*)0 + 0 is (char*). As I
read it, the whole rest of the paragraph depends on the directly
following condition:

If the pointer operand points to an element of an array
object, and the array is large enough, ...

Since (char*)0 does not point to an element of an array object the
I assume you refer to the sentence

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.

Are you sure this not dependent on the first condition cited above?
This sentence refers to "the result" of which we only know how it is
derived when the pointer operand points to an element of an array
object.

Or do I misunderstand this paragraph 8 so fundamentally?

urs

 Eric Sosman 06-16-2010 09:20 PM

Re: Arithmetic will null pointer

On 6/16/2010 4:20 PM, Richard Heathfield wrote:
> Urs Thuermann wrote:
>> Richard Heathfield <rjh@see.sig.invalid> writes:
>>
>>> The compiler is not required to diagnose such an addition, but the
>>> behaviour is undefined. See paragraph 8 of the section you quoted

>
> <snip>
>
>> I assume you refer to the sentence
>>
>> 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.

>
> You assume correctly.
>
>> Are you sure this not dependent on the first condition cited above?

>
> Yes. Since a null pointer doesn't point to an object, neither it nor the
> result can point to "elements of the same array object, or one past the
> last element of the array object", and therefore the behaviour is
> undefined.

Further to this point: Behavior is undefined if the Standard
says so explicitly, *or* if a requirement outside a constraint
section is violated, *or* if the Standard simply doesn't describe
the behavior at all. All of these are "equally undefined" (4p1).

When attempting arithmetic on a null-valued pointer, it's the
third of these situations: The Standard describes what happens if
the pointer points at or just after an object, but a null-valued
pointer doesn't do so. Therefore, the Standard's description does
not cover the case, and the behavior is "undefined by omission."

--
Eric Sosman
esosman@ieee-dot-org.invalid

 Seebs 06-16-2010 09:52 PM

Re: Arithmetic will null pointer

On 2010-06-16, Richard Heathfield <rjh@see.sig.invalid> wrote:
> Yes. Since a null pointer doesn't point to an object, neither it nor the
> result can point to "elements of the same array object, or one past the
> last element of the array object", and therefore the behaviour is undefined.

Okay, I haven't had any caffeine today, but.

What tells us that a null pointer cannot point one past the last
element of an array object?

I agree that nothing tells us that it *does* point one past the last
element of an array object. But could it?

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / usenet-nospam@seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!

 Keith Thompson 06-17-2010 01:07 AM

Re: Arithmetic will null pointer

Eric Sosman <esosman@ieee-dot-org.invalid> writes:
> On 6/16/2010 4:20 PM, Richard Heathfield wrote:
>> Urs Thuermann wrote:
>>> Richard Heathfield <rjh@see.sig.invalid> writes:
>>>> The compiler is not required to diagnose such an addition, but the
>>>> behaviour is undefined. See paragraph 8 of the section you quoted

>>
>> <snip>
>>
>>> I assume you refer to the sentence
>>>
>>> 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.

>>
>> You assume correctly.
>>
>>> Are you sure this not dependent on the first condition cited above?

>>
>> Yes. Since a null pointer doesn't point to an object, neither it nor the
>> result can point to "elements of the same array object, or one past the
>> last element of the array object", and therefore the behaviour is
>> undefined.

>
> Further to this point: Behavior is undefined if the Standard
> says so explicitly, *or* if a requirement outside a constraint
> section is violated, *or* if the Standard simply doesn't describe
> the behavior at all. All of these are "equally undefined" (4p1).
>
> When attempting arithmetic on a null-valued pointer, it's the
> third of these situations: The Standard describes what happens if
> the pointer points at or just after an object, but a null-valued
> pointer doesn't do so. Therefore, the Standard's description does
> not cover the case, and the behavior is "undefined by omission."

Actually, as Richard pointed out, the standard says explicitly that
it's undefined:

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*.

(Unless a null pointer points one past the last element of the array
object, as Seebs suggests.)

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

 Keith Thompson 06-17-2010 01:15 AM

Re: Arithmetic will null pointer

Seebs <usenet-nospam@seebs.net> writes:
> On 2010-06-16, Richard Heathfield <rjh@see.sig.invalid> wrote:
>> Yes. Since a null pointer doesn't point to an object, neither it nor the
>> result can point to "elements of the same array object, or one past the
>> last element of the array object", and therefore the behaviour is undefined.

>
> Okay, I haven't had any caffeine today, but.
>
> What tells us that a null pointer cannot point one past the last
> element of an array object?
>
> I agree that nothing tells us that it *does* point one past the last
> element of an array object. But could it?

In theory, I think so.

C99 6.3.2.3p3:

If a null pointer constant is converted to a pointer type,
the resulting pointer, called a _null pointer_, is guaranteed
to compare unequal to a pointer to any object or function.

An implementation for which a null pointer is equal to a pointer just
past the end of some object could break some seemingly reasonable
code (but only if it happens to be operating on that one object),
but I don't see anything in the standard that forbids it.

An almost-plausible scenario: A null pointer is represented as
all-bits-zero. Automatic objects are allocated on The Stack, which
grows from high addresses to low, and starts at the top end of the
around from 0xffffffff to 0. The last byte of the first allocated
object in the program (perhaps argc, perhaps the string pointed to
by argv[0], perhaps something else) occupies byte 0xffffffff.

I doubt that any such implementations actually exist.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

 Peter Nilsson 06-17-2010 03:16 AM

Re: Arithmetic will null pointer

Keith Thompson <ks...@mib.org> wrote:
> An almost-plausible scenario: A null pointer is represented
> as all-bits-zero. *Automatic objects are allocated on The
> Stack, which grows from high addresses to low, and starts
>*Pointer arithmetic quietly wraps around from 0xffffffff to
> 0. *The last byte of the first allocated object in the
> program (perhaps argc, perhaps the string pointed to
> by argv[0], perhaps something else) occupies byte
> 0xffffffff.
>
> I doubt that any such implementations actually exist.

Particularly as 0x00000000 would have to compare greater
than 0xffffffff for an object landing on that address.

In practice, implementations already have to allow
problems with 'one past the end' pointers in memory
allocations.

--
Peter

 Peter Nilsson 06-17-2010 05:25 AM

Re: Arithmetic will null pointer

Richard Heathfield <r...@see.sig.invalid> wrote:
> Seebs wrote:
> > What tells us that a null pointer cannot point one past
> > the last element of an array object?
> >
> > I agree that nothing tells us that it *does* point one
> > past the last element of an array object. *But could it?

>
> Who cares? Even if it did, there is no strictly conforming
> way to tell /which/ object it were pointing one past the end
> of,

Well, people do use one past the end pointers as sentinels,
e.g. in for loops. People also compare against null. Whilst
I can't think of a specific circumstance where one would
compare one past the end with null (directly or indirectly,)
it's not beyond the realms of possibility that some code
somewhere might actually rely on the equality not being
equal.

--
Peter

 Peter Nilsson 06-17-2010 06:38 AM

Re: Arithmetic will null pointer

Richard Heathfield <r...@see.sig.invalid> wrote:
> Peter Nilsson wrote:
> > Well, people do use one past the end pointers as sentinels,
> > e.g. in for loops.

>
> Yes, but you wouldn't use (NULL + n) as your sentinel, would
> you?

No. That's not my point following from Seebs comment.

> > People also compare against null. Whilst
> > I can't think of a specific circumstance where one would
> > compare one past the end with null (directly or indirectly,)

Change that...

> > it's not beyond the realms of possibility that some code
> > somewhere might actually rely on the equality not being
> > equal.

>
> Either "one past the end" is guaranteed not to be a null
> pointer, or it isn't. Right now, I'm in too much of a hurry
> to look it up. If it *is* guaranteed not to be a null pointer,
> then your scenario is of no consequence and this whole
> subthread is chasing a scotch mist. If it is *not* guaranteed
> not to be a null pointer, then code that assumes it isn't a
> null pointer is relying on a broken assumption.

But it seems a reasonable assumption.

Here's a contrived example:

T *col;
T *found = NULL;

for (col = vector; col < vector + N; col++)
{
if (something(*col))
found = col;
if (something_else(*col))
break;
}

/* did we find something and break at the same spot? */
/* assumption: one past end cannot be null */
if (found == col)
do_something();

Some might call that poor coding, some might call it
efficient.

--
Peter

 Stargazer 06-17-2010 07:36 AM

Re: Arithmetic will null pointer

On Jun 17, 4:15*am, Keith Thompson <ks...@mib.org> wrote:

[...]
> An almost-plausible scenario: A null pointer is represented as
> all-bits-zero. *Automatic objects are allocated on The Stack, which
> grows from high addresses to low, and starts at the top end of the
> around from 0xffffffff to 0. *The last byte of the first allocated
> object in the program (perhaps argc, perhaps the string pointed to
> by argv[0], perhaps something else) occupies byte 0xffffffff.
>
> I doubt that any such implementations actually exist.

It is forbidden for an implementation to do things this way: "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." (6.5.6[8])

In your proposal incrementing pointer to one past the last element of
an array does produce an overflow.

Daniel

All times are GMT. The time now is 06:52 PM.