views:

291

answers:

4

According to the responses in "Why subtract null pointer in offsetof()?" (and my reading of K&R), the C standard doesn't require that (size_t)((char *)0) == 0. Still, I've never seen a situation where casting a null pointer to an integer type evaluates to anything else.

If there is a compiler or scenario where (size_t)((char *)0) != 0, what is it?

+4  A: 

Well, as you know, the physical representation of null pointer of a given type is not necessarily all-zero bit pattern. When you forcefully convert a pointer (any pointer) value to integer type, the result is implementation defined, but normally (and that's the intent) the numerical value of the pointer - the numerical address - remains unchanged, if possible. This means that if on a given platform a null pointer of type char * is represented by 0xBAADF00D pattern (for example), the above expression will evaluate to 0xBAADF00D, and not to zero. Of course, for that you'd need a platform with non-zero null-pointers. I personally never worked with such platforms, although I heard about a number of real platforms like that out there (like, in the realm of embedded platforms it is not something unusual).

Moreover, as an additional note, null pointer values of different types can have different physical representations, meaning that in theory you can get different values from (size_t) ((int *) 0), (size_t) ((char *) 0) and (size_t) ((double *) 0). But that would be a rather exotic situation, albeit perfectly possible from the point of view of abstract C language.

P.S. Read here (C FAQ) for some examples of actual platforms with non-zero null pointers.

AndreyT
I understand the theoretical arguments (which you explain well), but I'm looking for examples of actual systems where casting a null pointer to an integer results in a non-zero value in practice.
Bruce Christensen
@Bruce Christensen: See the link to C FAQ in in P.S.
AndreyT
Bruce Christensen
@Bruce Christensen: Standard library implementation is platform-specific. It is not required to be portable at the level of the source code. So, if on some platform (Linux or not) the null-pointer is not zero, the implementatuion of `offsetof` for that platform would be different. It is a simple as that.
AndreyT
i worked on a machine (that compiled C code) that had 0xFFFFFFFF as null (Honeywell Bull DPS7). At the time it seemed pefectly natural to me (every machine has an address 0 so making it 'illegal' really is strange)
pm100
@AndreyT: +1 - thanks for the link.
Michael Burr
@AndreyT: The fact that standard library implementation is platform-specific is exactly my point: on every platform that runs Linux (which is most of them these days, it seems), (size_t)((char *)0) == 0. That suggests that there are few, if any, modern systems where casting null to int evaluates to non-zero.
Bruce Christensen
IBM CICS uses `0x80000000` as its null pointer value (IIRC).
Loadmaster
+1  A: 

The only thing that the C standard requires of a null pointer's runtime representation is (6.3.2.3/3 "Pointers"):

...the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function. Conversion of a null pointer to another pointer type yields a null pointer of that type.

Any two null pointers shall compare equal.

Your question is an interesting one, though. Personally, I'm unaware of a platform that doesn't use the runtime value 0 to represent a null pointer. However, the standard doesn't require it, so if you can avoid the assumption in your code, why not?

I'd also be interested in anyone who knows of a system that uses a non-zero runtime value for a null pointer.

Michael Burr
A: 

This doesn't apply to char* or even C, but a smart pointer class which indexes into an array might choose to represent NULL as -1 because 0 is a valid array index.

Considering the idiom of memset( my_new_struct, 0, sizeof my_new_struct );, even a debugging-centric system is unlikely to break that identity.

Potatoswatter
+1  A: 

The C99 standard says that when you convert an integer value 0 to a pointer, it becomes a NULL pointer. So ((char*)0) is a NULL pointer. A NULL pointer need not have an actual binary representation of 0. It can be, for example 0x12345678.

The C standard further states that when you convert a NULL pointer to an integer constant, the result is "implementation-defined". In reality, what compilers do is simply cast the use the numerical value of the pointer to the corresponding integer value, as AndreyT said. So in the example above, the integer value might end up being 0x12345678, though technically it could be anything at all (ie. the compiler is allowed to say "converting a NULL pointer back to an integer value results in value 0xDEADBEEF"). Note that this means that even on platforms where the NULL pointer has the value 0, the compiler is allowed to convert it to an arbitrary integer value upon conversion. In reality, however, no compilers do that because it would be fairly insane.

So, yes, the C standard allows a lot of things. In reality, any platform you are likely to work on will represent a NULL pointer as 0 and converting a NULL pointer to an integer value will result in 0. Look here (section 1.14) for a list of some exceptions of (obscure) architectures which do not use 0 for a NULL pointer.

RarrRarrRarr