Pointer arithmetic involving NULL pointers

  • Thread starter Christopher Benson-Manica
  • Start date
C

Christopher Benson-Manica

Is adding 0 to a pointer to non-void that is equal to NULL legal?

int *p=NULL;
p+=0;
 
E

Eric Sosman

Christopher said:
Is adding 0 to a pointer to non-void that is equal to NULL legal?

int *p=NULL;
p+=0;

Never considered it before, but I think it's undefined.

6.5.6 Additive operators
/8/ [...] 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. [...]

Since `p' above does not point to any element of any array
object, the "otherwise" holds.

If you don't mind my asking, what are you trying to do?
I've added zero to a pointer value plenty of times, as in

char *p = string_with_possible_leading_spaces;
p += strspn(p, " \t\f\n\r";

.... but I can't recall being tempted to do any such thing
with a NULL value. What's up?
 
D

Dave Vandervies

Is adding 0 to a pointer to non-void that is equal to NULL legal?

int *p=NULL;
p+=0;

No; pointer addition is only defined for pointers to or one past a valid
object, so adding anything (even 0) to a null pointer is undefined.
(N869 6.5.6#8, see also #7.)

(But the sigmonster made a good choice today.)


dave
 
K

Keith Thompson

Christopher Benson-Manica said:
Is adding 0 to a pointer to non-void that is equal to NULL legal?

int *p=NULL;
p+=0;

No, it invokes undefined behavior. C99 6.5.6p4 says:

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

There's no stated exception for adding 0. The C90 standard has
similar or identical wording.

On most implementations, the operation won't cause a trap, and the
result will compare equal to NULL -- which is, of course, a valid
consequence of undefined behavior.
 
S

Spoofed Existence (astalavista.net)

Christopher said:
Is adding 0 to a pointer to non-void that is equal to NULL legal?

int *p=NULL;
p+=0;

A pointer is nothiner else than a piece of memory with the right size to
store a memory address. Normally this is 4 bytes, but this may be different
on other different computers. You can do anything with this memory you can
do with other memory. This includes adding things to it - in this case 0.
The problem which make things illegal isn't that the pointer *is* NULL (=
0), but that the data the pointer points to is accessed. The pointer points
to the memory address 0, which can't be accessed.

So p += 0; would be valid, but it would keep the pointer to 0 (NULL). So
accessing this memory still is invalid. But with the pointer itself, you
can do anything. As long as the data the pointer points to isn't accessed.

But why not just use an "int" for example. Should you ever need the data it
points to, you can simply use:
(int*)theinteger




Hope that helps,
Spoofed Existence
 
C

Christopher Benson-Manica

Eric Sosman said:
... but I can't recall being tempted to do any such thing
with a NULL value. What's up?

Well, the situation is something like the following:

void foo( char *buf, int bufsize )
{
bar( buf, buf?bufsize:0 );
/* Call other functions like bar, with the same parameters */
}

void bar( char *buf, int bufsize )
{
int bytes_remaining=bufsize;

bytes_remaining-=snprintf( buf+(bufsize-bytes_remaining), bytes_remaining, "Hello, world!\n" );

/* Call snprintf in the same way several more times */
}

snprintf() is C99, correct?

Assuming I've made no other errors here, this strikes me as being
fairly concise code. Of course, I could call bar as

bar( buf?buf:"", buf?bufsize:0 );

and eliminate the probable undefined behavior, but presumably nothing
catastrophic will occur on the particular real implementation I'm
using with the code as is.
 
C

Christian Bau

"Spoofed Existence (astalavista.net)"

Warning to every reader: What follows is absolutely wrong.
A pointer is nothiner else than a piece of memory with the right size to
store a memory address. Normally this is 4 bytes, but this may be different
on other different computers. You can do anything with this memory you can
do with other memory. This includes adding things to it - in this case 0.
The problem which make things illegal isn't that the pointer *is* NULL (=
0), but that the data the pointer points to is accessed. The pointer points
to the memory address 0, which can't be accessed.

So p += 0; would be valid, but it would keep the pointer to 0 (NULL). So
accessing this memory still is invalid. But with the pointer itself, you
can do anything. As long as the data the pointer points to isn't accessed.

Please stop giving incorrect advice.
 
K

Keith Thompson

"Spoofed Existence (astalavista.net)"
A pointer is nothiner else than a piece of memory with the right size to
store a memory address. Normally this is 4 bytes, but this may be different
on other different computers.

4 bytes is a common size for pointers, but there's nothing abnormal
about other sizes.
You can do anything with this memory you can
do with other memory. This includes adding things to it - in this case 0.

You can do anything you want to with the *memory* (e.g., if you treat
it as an array of unsigned char), but the language limits what you can
do with it as a pointer. In particular, performing arithmetic on a
null pointer invokes undefined behavior, as has been explained
elsewhere in this thread.
The problem which make things illegal isn't that the pointer *is* NULL (=
0), but that the data the pointer points to is accessed. The pointer points
to the memory address 0, which can't be accessed.

No, the problem is precisely that it's a null pointer. As far as the
C language is concerned, a null pointer doesn't point to "memory
address 0"; it doesn't point to *anything*. (A null pointer is not
necessarily represented as all-bits-zero; see the FAQ.)
So p += 0; would be valid, but it would keep the pointer to 0 (NULL). So
accessing this memory still is invalid. But with the pointer itself, you
can do anything. As long as the data the pointer points to isn't accessed.

That's incorrect. On many systems, p += 0; will result in p being
equal to NULL; that's just one of the many possible consequences of
undefined behavior.
 
C

Christopher Benson-Manica

Christopher Benson-Manica said:
bar( buf?buf:"", buf?bufsize:0 );

Or, to post code that's actually legal,

if( !buf ) {
buf="";
bufsize=0;
}

Maybe I should A) go home, and B) never use the trinary operator in
function calls again. Sorry.
 
D

DD

Keith Thompson said:
"Spoofed Existence (astalavista.net)"


4 bytes is a common size for pointers, but there's nothing abnormal
about other sizes.
0.

You can do anything you want to with the *memory* (e.g., if you treat
it as an array of unsigned char), but the language limits what you can
do with it as a pointer. In particular, performing arithmetic on a
null pointer invokes undefined behavior, as has been explained
elsewhere in this thread.


No, the problem is precisely that it's a null pointer. As far as the
C language is concerned, a null pointer doesn't point to "memory
address 0"; it doesn't point to *anything*. (A null pointer is not
necessarily represented as all-bits-zero; see the FAQ.)
Isn't it true that in most applications "NULL" is defined as 0 ? So
essentially in most applications the null pointer would be pointing to
address 0. Correct me if I am wrong.
accessed.

That's incorrect. On many systems, p += 0; will result in p being
equal to NULL; that's just one of the many possible consequences of
undefined behavior.
 
G

Gordon Burditt

Isn't it true that in most applications "NULL" is defined as 0 ? So

No! Applications have no business defining NULL at all, especially
if any of the ANSI C headers that are supposed to define NULL are included
(such as said:
essentially in most applications the null pointer would be pointing to
address 0. Correct me if I am wrong.

The presence of:
#define NULL 0
or
#define NULL ((void *) 0)
in an ANSI C header file does not prohibit the implementation from
using a bit pattern of 0xdeadbeef for a null pointer. The use of
0xdeadbeef is not required, even if pointers are 32 bits. The use
of 0xdeadbeefdeadbeef is not required, even if pointers are 64 bits.

This is one possible outcome, but it is not guaranteed. A smegmentation
violation due to loading an invalid value into a smegment register
is another. Undefined is undefined.

Incorrect. With the pointer itself, the *IMPLEMENTATION* can do
anything, since you invoked the wrath of undefined behavior,
regardless of how painful, embarassing, or expensive it is for you.
You don't get to choose.
As long as the data the pointer points to isn't
accessed.

Gordon L. Burditt
 
S

Spoofed Existence (astalavista.net)

Christian said:
"Spoofed Existence (astalavista.net)"

Warning to every reader: What follows is absolutely wrong.

accessed.

Please stop giving incorrect advice.

I'm sorry. The compiler I use, gcc 3.3.4, defines NULL as (void*)0. Also,
gcc can use mathematic expressions on it, although some things will need
some changes.
So I assumed this was just a standard. Well, I never read about any
standards, and I basically learned C by trying things, and by reading. But
I never really learned about other compilers than gcc. Might be a good idea
to do it sometime.
 
K

Keith Thompson

"Spoofed Existence (astalavista.net)"
I'm sorry. The compiler I use, gcc 3.3.4, defines NULL as (void*)0. Also,
gcc can use mathematic expressions on it, although some things will need
some changes.

The definition of NULL is determined by the system's headers, which
may be, but aren't necessarily, from the same source as your compiler.

The definition of NULL as (void*)0 does *not* necessarily mean that
the representation of a null pointer is all-bits-zero.

(GNU C allows arithmetic on void* pointers; standard C does not.)
 
C

Christian Bau

"Spoofed Existence (astalavista.net)"
The compiler I use, gcc 3.3.4, defines NULL as (void*)0.

Yes, and that is completely irrelevant. The C language defines that "0"
and "(void*) 0" have to be specifically recognised by the compiler and
then have to be replaced by a null pointer. Whatever a null pointer is.
Also,
gcc can use mathematic expressions on it, although some things will need
some changes.
So I assumed this was just a standard.

The original question was: Is pointer arithmetic with null pointers
undefined behavior? Undefined behavior means: Anything, just absolutely
anything, can happen. And "anything can happen" includes that it seems
to work if you use the current version of the gcc compiler.
Well, I never read about any
standards, and I basically learned C by trying things, and by reading. But
I never really learned about other compilers than gcc. Might be a good idea
to do it sometime.

If you learn about the C Standard itself instead of other compilers,
that would have the advantage that you learn what exactly is
_guaranteed_ to work and what is _not guaranteed_ to work. If something
is guaranteed to work then you don't have to learn about other
compilers, it will work.

If something is not guaranteed to work, like adding 0 to a null pointer,
then you are asking for trouble if you use a different compiler, or if
you use a different version of the compiler, or if you turn optimisation
on or off, or if you slightly rearrange your code in a way that
shouldn't make any difference. In all these cases, something that
"worked" by coincidence can suddenly stop working.
 
D

Derrick Coetzee

Christian said:
If you learn about the C Standard itself instead of other compilers,
that would have the advantage that you learn what exactly is
_guaranteed_ to work and what is _not guaranteed_ to work. If something
is guaranteed to work then you don't have to learn about other
compilers, it will work.

You make the opposite error - the assumption that other compilers are
compliant. If a particular noncompliant compiler is influential enough,
people writing portable code will strive to observe its quirks as well
as the standard. A good example is Visual C++'s problem with the scope
of variables declared in for loop initializers (although that's not a C
example; I think most modern C compilers are pretty much compliant, right?)
 
C

Chris Barts

I think most modern C compilers are pretty much compliant, right?

No important compiler is C99 compliant. (C99 is looking more and more like
a dead issue as time goes by, and it's difficult to imagine that
nonconformance with C99 will ever be a hindrance to a compiler's
popularity.) The GNU C Compiler is in the happy position of having some of
its historical extensions codified in C99, so it's partially there with
the stated intent of full support, IIRC.

C89 is very widely supported, and C90 can usually be assumed, as well. C89
is what this newsgroup implicitly assumes when it says "standard", and
C99-specific things are always introduced as such. However, I don't know
of any compiler that correctly compiles only C89 (as opposed to C89 plus
extensions) by default.
 
M

Michael Wojcik

A pointer is nothiner else than a piece of memory with the right size to
store a memory address.

While we're pointing out errors here, I'd like to note that a pointer
can contain something other than a simple address; and there is at
least one implementation (AS/400 ILE C) which I believe is conforming
and which does so. (ILE C pointers contain some kind of reference to
a "memory space" and an offset into that space, and possibly other
information; some of this can be seen by displaying the value of a
valid non-null pointer with the "%p" printf specifier.)

So besides not assuming that null pointers have the value all-bits-
zero, you shouldn't assume that non-null pointers have just a simple
address.

--
Michael Wojcik (e-mail address removed)

Only the obscene machine has persisted
jerky and jockeying and not knowing why
I have never existed. Nor should. -- George Barker
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top