Value of int NULL

P

polas

Afternoon all,

I have some code (which I thought was OK, but now appreciate is
probably not by the standard) which contains

int a;
......
if (a==NULL)
{
....
}

Compiling with GCC was fine - no problem, however with PGI gave an
error. Therefore, I assume that checking that an integer contails NULL
is not allowed by the standard. But if a is declared like that,
without a value, then what is its value (or is it undetermined) at
that point, and is there a way to check, without using dummy values,
whether an integer variable has had a value assigned to it?

I also notice that, although it produces a cast warning, PGI allows me
to assign NULL to an integer i.e. int a=NULL; What, or is it
implementation specific, is the actual value of the variable in this
case?

Cheers,
Nick
 
R

Richard Bos

polas said:
Afternoon all,

I have some code (which I thought was OK, but now appreciate is
probably not by the standard) which contains

int a;
.....
if (a==NULL)
{
...
}

Compiling with GCC was fine - no problem, however with PGI gave an
error. Therefore, I assume that checking that an integer contails NULL
is not allowed by the standard.

An integer cannot contain a null pointer.

NULL is a null pointer constant. It _may_ be defined as 0 (or
equivalent), which means that it will look exactly like the null pointer
constant, and can, confusingly, be used in an integer context rather
than a pointer context. It may also be defined as ((void *)0), or
equivalent, in which case it is a pointer, not an integer, and cannot be
directly compared to an integer.
In either case, thought, NULL is still the null pointer constant, and is
at least conceptually a pointer, not an integer, and should never be
used to represent integer values.
But if a is declared like that, without a value, then what is its value
(or is it undetermined)

If it is declared at function scope without "static", it is indeed
undetermined, and may even be a trap representation. If it is declared
at file scope, or with "static", it is always 0 - that is, zero, _not_ a
null pointer, even where NULL looks like 0.
that point, and is there a way to check, without using dummy values,
whether an integer variable has had a value assigned to it?

No. And even where NULL looks like 0, comparing a to NULL does not do
what you want anyway, because the 0 to which static objects are
initialised is exactly the same as the 0 you get when you explicitly
write

int a=0;

Richard
 
S

Salvatore Iovene

Afternoon all,
Hi.

I have some code (which I thought was OK, but now appreciate is
probably not by the standard) which contains

int a;
.....
if (a==NULL)
{
...
}

Compiling with GCC was fine - no problem, however with PGI gave an
error. Therefore, I assume that checking that an integer contails NULL
is not allowed by the standard. But if a is declared like that,
without a value, then what is its value (or is it undetermined) at
that point, and is there a way to check, without using dummy values,
whether an integer variable has had a value assigned to it?

The value of an uninitialized variable is undefined. If you want to check
it out, try to print your integer.
There's no way to check if ever a value was assigned to a variable. But
you can inizialize it to something, and later check if it's still like that.
E.g. if you expect a positive number to be assigned to your integer,
you can initialize it to -1 and later check if a != -1.
I also notice that, although it produces a cast warning, PGI allows me
to assign NULL to an integer i.e. int a=NULL; What, or is it
implementation specific, is the actual value of the variable in this
case?

NULL is defined to be 0, that's why it works. Although, you should only
use it for pointers, to indicate that a pointer points to nothing. So the
compiler issues a warning so that you'd make sure you're using NULL properly.

Hope this helps.

Cheers,
Salvatore.
 
S

santosh

polas said:
Afternoon all,

I have some code (which I thought was OK, but now appreciate is
probably not by the standard) which contains

int a;
.....
if (a==NULL)
{
...
}

Compiling with GCC was fine - no problem, however with PGI gave an
error. Therefore, I assume that checking that an integer contails NULL
is not allowed by the standard.

It is allowed, but implementation defined. NULL is a macro that expands
to a null pointer constant. It could be either a literal 0 or an
expression like (void*)0 or something else.

Since you cannot be sure that it is not a literal 0 you cannot safely
compare it to integer values. It is *meant* to be used for initialising
and comparing with pointers, not integers. For integers just use 0

if (a == 0)

is better and clearer. Similarly for characters you can use

if (c == '\0')

although here using 0 instead of '\0' is perfectly portable, it is
neverthelss, not that readable.
But if a is declared like that,
without a value, then what is its value (or is it undetermined) at
that point, and is there a way to check, without using dummy values,
whether an integer variable has had a value assigned to it?

An uninitialised object has an indeterminate value. To be perfectly
safe, you should not even inspect this value as it might contain a trap
representation. You can only use an object after it has been explicitly
or implicitly initialised to some value.
I also notice that, although it produces a cast warning, PGI allows me
to assign NULL to an integer i.e. int a=NULL; What, or is it
implementation specific, is the actual value of the variable in this
case?

This will vary from implementation to implementation. It's
implementation defined what value will be written to a pointer if it is
assigned NULL. It is also implementation defined what value will be
produced as a result of converting a pointer to an integer.

On many platforms it will be zero, but this is not guaranteed by the C
Standard.
 
P

polas

It isn't disallowed, but it's not required to work. The
implementation's headers can define the macro NULL to expand
to either 0 or (void*)0 (or to some other expression equivalent
to one or the other of these). If NULL expands to 0 (or an
equivalent) then the test is fine: `if (a==0)' is perfectly
legal. But if NULL expands to (void*)0 (or an equivalent)
then the test is no good: `if (a==(void*)0)' tries to compare
an `int' number with a `void*' pointer, but numbers and pointers
aren't comparable.

Moral: NULL is intended to be used in pointer contexts,
and using it with non-pointers is a bad idea. If it happens
to work, that's more by good luck than by good management.

Moral #2: Pointers are not numbers, and numbers are not
pointers.


The value of an `auto' or `register' variable that has no
initializer and has not been written to is indeterminate. In
less formal terms, the variable is "initialized to garbage."
Since the "garbage" could be anything at all, including any
value you chose to compare it to, there's no reliable way to
distinguish trash from treasure. In this respect, C programming
is like real life.

It is even possible that a mere attempt to compare the
un-set variable to something might make the program misbehave.
In some implementations, some kinds of garbage can be what
are called "trap representations," bit patterns that cause the
machine to raise a signal or otherwise go off the rails. Such
things are rare (maybe nonexistent) for integer variables, but
are not unheard-of for floating-point variables, especially on
systems that provide "signalling NaNs."


If NULL expands to 0, the value of `a' is zero. If NULL
expands to (void*)0, the compiler must emit a diagnostic message
and is allowed to reject the program. If it chooses to accept
the program anyhow, the value of `a' is whatever the compiler
chooses; the C language doesn't dictate what kinds of repairs a
compiler can make to an erroneous program.

Thanks very much for the replys everyone... they have answered my
questions and I have also learnt a few things about NULL.

Cheers for the help,
Nick
 
C

Chris M. Thomasson

polas said:
Afternoon all,

I have some code (which I thought was OK, but now appreciate is
probably not by the standard) which contains

int a;
.....
if (a==NULL)
{
...
}

Compiling with GCC was fine - no problem, however with PGI gave an
error. Therefore, I assume that checking that an integer contails NULL
is not allowed by the standard. But if a is declared like that,
without a value, then what is its value (or is it undetermined) at
that point, and is there a way to check, without using dummy values,
whether an integer variable has had a value assigned to it?

Why are you comparing an `int' to NULL?



I also notice that, although it produces a cast warning, PGI allows me
to assign NULL to an integer i.e. int a=NULL; What, or is it
implementation specific, is the actual value of the variable in this
case?

On some arch, a null pointer may not represent a value in which all bits are
zero. Keep in mind that on such arch the following is fine:

void* ptr = [...];

if (ptr == 0) {
printf("%p", ptr);
}

and could output something that is not all zeros. The compiler works its
magic and just does the right thing. AFAICT, a conforming platform could
represent a NULL pointer as 0xFFFFFFFF. The compiler would convert above
code to something like:

void* ptr = [...];

if (ptr == (void*)0xFFFFFFFF) {
printf("%p", ptr);
}



So be it...
 
C

CBFalconer

polas said:
I have some code (which I thought was OK, but now appreciate is
probably not by the standard) which contains

int a;
.....
if (a == NULL) ...

NULL is a pointer value for pointers that point nowhere, and cannot
be dereferenced. It is NOT a substitute for zero. If you want
zero, write 0 (or a suitably defined macro).
 
B

Barry Schwarz

The value of an uninitialized variable is undefined. If you want to check

Nit: Technically the value is indeterminate.
it out, try to print your integer.

Bigger than a nit: Any attempt to evaluate an indeterminate value,
including passing that value to a function like printf, invokes
undefined behavior.
 
B

Barry Schwarz

It isn't disallowed, but it's not required to work. The
implementation's headers can define the macro NULL to expand
to either 0 or (void*)0 (or to some other expression equivalent
to one or the other of these). If NULL expands to 0 (or an
equivalent) then the test is fine: `if (a==0)' is perfectly
legal. But if NULL expands to (void*)0 (or an equivalent)
then the test is no good: `if (a==(void*)0)' tries to compare
an `int' number with a `void*' pointer, but numbers and pointers
aren't comparable.

Moral: NULL is intended to be used in pointer contexts,
and using it with non-pointers is a bad idea. If it happens
to work, that's more by good luck than by good management.

Personal opinion: Bad luck rather than good.
 
K

Keith Thompson

polas said:
I have some code (which I thought was OK, but now appreciate is
probably not by the standard) which contains

int a;
.....
if (a==NULL)
{
...
}

Compiling with GCC was fine - no problem, however with PGI gave an
error. Therefore, I assume that checking that an integer contails NULL
is not allowed by the standard. But if a is declared like that,
without a value, then what is its value (or is it undetermined) at
that point, and is there a way to check, without using dummy values,
whether an integer variable has had a value assigned to it?

There is no distinct value for type int that says it's not a number.
Other languages do have such things (for example, in Perl a scalar
variable with the value 0 is distinct from one with the value undef),
but C doesn't.

A variable declared within a function with no initialization has an
indeterminate value. Just attempting to read that value invokes
undefined behavior. The most likely result is that you'll get some
arbitrary value, whatever happens to be in memory, but you shouldn't
depend on it.

If you're lucky, your compiler might be able to warn you if you try to
access an uninitialized variable. This typically requires extra
compiler options, including optimization options to force the compiler
to do the analysis necessary to detect this.

In general, you just have to be careful not to access uninitialized
variables in the first place. You can't count on your system
detecting it for you, either at compile time or at run time.

[...]
 
K

Keith Thompson

santosh said:
It is allowed, but implementation defined. NULL is a macro that expands
to a null pointer constant. It could be either a literal 0 or an
expression like (void*)0 or something else.
[...]

It can't be ``(void*)0''. It can be ``((void*)0)''.

C99 7.1.2p5:

Any definition of an object-like macro described in this clause
shall expand to code that is fully protected by parentheses where
necessary, so that it groups in an arbitrary expression as if it
were a single identifier.

The version without parentheses would break ``sizeof NULL''.

(There's a nitpicking argument that ``((void*)0)'' isn't allowed, but
I'm sure the intent is to allow it, and many implementations define it
that way anyway. The problem is 6.5.1p5, which *doesn't* say that a
parenthesized null pointer constant is a null pointer constant.)
 
S

santosh

Keith Thompson wrote:

A variable declared within a function with no initialization has an
indeterminate value. Just attempting to read that value invokes
undefined behavior. The most likely result is that you'll get some
arbitrary value, whatever happens to be in memory, but you shouldn't
depend on it.

If you're lucky, your compiler might be able to warn you if you try to
access an uninitialized variable. This typically requires extra
compiler options, including optimization options to force the compiler
to do the analysis necessary to detect this.

In general, you just have to be careful not to access uninitialized
variables in the first place. You can't count on your system
detecting it for you, either at compile time or at run time.

[...]

To be very precise the word access in the text above should be
substituted with the word read, as according to the C Standard, the
definition of access includes modification, and that is certainly fine
with uninitialised objects.
 
B

Ben Bacarisse

Barry Schwarz said:
Nit: Technically the value is indeterminate.


Bigger than a nit: Any attempt to evaluate an indeterminate value,
including passing that value to a function like printf, invokes
undefined behavior.

I think this is too strong. Doing anything with an indeterminate
value is a Very Bad Idea, but it is not always UB. The reason is that
an indeterminate value is simply either a valid value or a trap
representation. On a system without trap reps., the behaviour is
entirely defined (although unpredictable). It is much simpler to say
"that's UB", because that is what it is in the most general case, but
on many systems it is not.
 
S

santosh

Keith said:
santosh said:
It is allowed, but implementation defined. NULL is a macro that
expands to a null pointer constant. It could be either a literal 0 or
an expression like (void*)0 or something else.
[...]

It can't be ``(void*)0''. It can be ``((void*)0)''.

Yes. I should've realised that.

[ ... ]
(There's a nitpicking argument that ``((void*)0)'' isn't allowed, but
I'm sure the intent is to allow it, and many implementations define it
that way anyway. The problem is 6.5.1p5, which *doesn't* say that a
parenthesized null pointer constant is a null pointer constant.)

Has a DR been published for this?
 
K

Keith Thompson

santosh said:
Keith Thompson wrote: [...]
In general, you just have to be careful not to access uninitialized
variables in the first place. You can't count on your system
detecting it for you, either at compile time or at run time.

[...]

To be very precise the word access in the text above should be
substituted with the word read, as according to the C Standard, the
definition of access includes modification, and that is certainly fine
with uninitialised objects.

Quite right, thank you.
 
K

Keith Thompson

santosh said:
Keith Thompson wrote: [...]
(There's a nitpicking argument that ``((void*)0)'' isn't allowed, but
I'm sure the intent is to allow it, and many implementations define it
that way anyway. The problem is 6.5.1p5, which *doesn't* say that a
parenthesized null pointer constant is a null pointer constant.)

Has a DR been published for this?

Not as far as I can tell. The list of C99 DRs is at
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/summary.htm>.
The word NULL doesn't appear in any of their titles.
 
B

Ben Bacarisse

pete said:
I don't consider that point to be valid.
An implementation is free to define *everything*
that the C standard says is undefined.
That doesn't mean that nothing is undefined.

I don't know what we are disagreeing about. The implementation *can*
say that int (the specific case in question) has trap representations
and thus make the construct (int a; printf("%d\n", a);) undefined. In
other words, I agree that an implementation can make this UB, but only
by one route -- having trap reps. for the int type.

But if int does not have trap representations then the definition of
an indeterminate value leaves no room for undefined behaviour that I
can see. printf must be able to print all valid values for an int
object.
However, the evaluation of an uninitialized
unsigned char object is not undefined,
because an object of that type can't have a trap representation.

Agreed.
 
B

Ben Bacarisse

pete said:
That's what undefined behavior is.


Undefined behavior requires nothing more
than a lack of interest by the C standard committee
in defining a certain code construct.

As is often the case I have no idea if we agree or not. I agree with
everything you have said except where you said "I don't consider that
argument to be valid".
 
H

Harald van Dijk

Code that attempts to read an uninitialized int object, is code that
contains undefined behavior, no matter which implementation is used to
attempt to translate and execute the code.

Programs that read uninitialised int objects on implementations where int
has no trap representations have defined behaviour. A strictly conforming
program can calculate the number of padding bits and check whether INT_MIN
< -INT_MAX. Combine the two and you find that there are situations where a
strictly conforming program can read uninitialised int objects.
However, the evaluation of an uninitialized
unsigned char object is not undefined,
because an object of that type can't have a trap representation.

Why do you believe this does not apply to other types as well?
 
C

CBFalconer

pete said:
.... snip ...

However, the evaluation of an uninitialized unsigned char object
is not undefined, because an object of that type can't have a
trap representation.

However the pointer to it can (assuming the pointer exists).
 

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,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top