Sign in to follow this  
ToohrVyk

C++ null pointers

Recommended Posts

In C, the following code is not guaranteed to set the pointers a and b to NULL:
typedef struct { int *a, *b; } S;

int main() {
  S s;
  memset(&s,0,sizeof S);
}
Does this problem also exist in C++, or is the C++ standard also unspecific about NULL pointer representation?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
In C, the following code is not guaranteed to set the pointers a and b to NULL:

Didn't know that, whats the reason do you know?, or have a link to an example?
I would have thought setting the memory to 0 would work.

Share this post


Link to post
Share on other sites
Quote:
Original post by QSlash
It shold be set to 0 both in c and c++.but the direct way is: S s ={0};


1° I know that it is set to 0. My question is, is it set to null?
2° For the purposes of the problem, let us assume that memory is set to zero, as opposed to initialized with zero.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Thanks for the link ToohrVyk thats interesting.
Have you looked at the C++ standard?

Share this post


Link to post
Share on other sites
I would have, but my dead-tree-paste version is at home right now, so I don't have access to it, and it isn't legally available online as far as I know.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
NULL is either defined as (void*)0 or 0, so it IS null.

Share this post


Link to post
Share on other sites
Quote:

I would have, but my dead-tree-paste version is at home right now, so I don't have access to it, and it isn't legally available online as far as I know.

Isn't it? I found it available online in pdf format a while back. Was that illegal?
*feels guilty*

Share this post


Link to post
Share on other sites
Quote:
NULL is either defined as (void*)0 or 0, so it IS null.

Completely false, (void*)0 is not valid and other representations is valid.
Quote:
The macro NULL is an implementation-defined C++ null pointer constant in this International Standard(4.10).180)

180) Possible definitions include 0 and 0L, but not (void*)0.


The interesting part of the C++ standard is:
Quote:
A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of pointer to object or pointer to function type. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (4.4).

I can't see it make any claims that a null pointer is guarenteed to be 0, it's guarenteed to evalute to 0, but its representation can be different. There may be something in the C++ standard which implicitely states that the representation is guarenteed to be 0, but I haven't heard about such a thing.

Share this post


Link to post
Share on other sites
Quote:
Original post by Spoonbender
Quote:

I would have, but my dead-tree-paste version is at home right now, so I don't have access to it, and it isn't legally available online as far as I know.

Isn't it? I found it available online in pdf format a while back. Was that illegal?
*feels guilty*


The actual standard isn't legally available for free, most (all?) of the drafts for the standards are available though, and they are pretty close to the actual standard.

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
NULL is either defined as (void*)0 or 0, so it IS null.


Not in C. (int)1.5f isn't 1.5f, and (void*)0 isn't 0. The C standard ensures that the 0 literal, when evaluated in a pointer context, is transformed into a NULL pointer. In C, the NULL pointer may or may not be represented as an integer-sized block of memory filled with zero bits. When evaluated in a boolean context (such as an if) clause, any pointers but the NULL pointer evaluate to true, while the NULL pointer evaluates to false.

Note that C does not guarantee that:

  • Setting all the bits of a pointer to zero creates a NULL pointer (as a matter of fact, several machines have a non-zero NULL pointer).
  • Setting a pointer to a zero-valued variable (as in int x = 0; void* y = x;) creates a NULL pointer.


In short, the only safe way to create a NULL pointer in C is through the compile-time conversion of the 0 literal into a pointer. Merely setting the pointer to zero is not enough.

Share this post


Link to post
Share on other sites
Quote:

There may be something in the C++ standard which implicitely states that the representation is guarenteed to be 0,

It states that the value representation of pointers is implementation defined.

However, it is guaranteed that a constant expression that evaluates to zero (during assignment, initialization or comparison of a pointer) is converted to value (the null pointer) and that this value is guaranteed to be distinguishable from a pointer to anything else. This doesn't mean that that null pointer has the same bit pattern as zero, however.

So, in your case, memset() is not a safe way set the pointers to null, because it will simply copy the bitpattern of zero into them. Then need to explitly be assigned or initialized to zero. There's no other way.

EDIT: Eh, I was slow.

Share this post


Link to post
Share on other sites
The truth is it doesn't matter what the C++ spec says, it all depends on what you actually need. Not to sound pessimistic but the truth is that to develop for all architectures is essentially impossible, since the various querks even in the compilers would make program maintenence a nightmare and not engineeringly 'sane'.

What I think you should do is decide whether to natively support architectures that use non 0 null pointers or whether to search for all usages of pointers at a later date to fix any issues caused by ignoring them.

If you decide to support them then just add a null definition to your project, this will work on almost all architectures (some operator overloading may be needed on more exotic machines for the operator == to work but that's ok). Otherwise use an is_null predicate for the best compatibility.

Of course if you only need to deal with 'real' systems that tend to maintain compatibility with more usual architectures then assuming 0 (and therefore also NULL) will suffice.

ps. on a side note you might want to see if the spec indicates whether pointer 'truth' value is always guarantee'd to be correct, but I believe it doesn't (unfortunately I don't have a copy of the spec).

Good Luck

Lorenz

edit: lol, i guess someone already got the answer in here anyway.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by ToohrVyk
In C, the following code is not guaranteed to set the pointers a and b to NULL:

typedef struct { int *a, *b; } S;

int main() {
S s;
memset(&s,0,sizeof S);
}

Does this problem also exist in C++, or is the C++ standard also unspecific about NULL pointer representation?


Going back to the example then, the safe method(if the real version was as simple as this) would be:
Quote:

struct S
{
S():a(NULL),b(NULL){}
int* a,*b;
};

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Oops
Quote:
rvalue of integer type that evaluates to zero.

a(0),b(0) is valid

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
CTar, going to my std headers it has this written:
#define NULL (void*)0
So its not my fault it isnt actually "standard".

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
CTar, going to my std headers it has this written:
#define NULL (void*)0
So its not my fault it isnt actually "standard".

But it is your fault you're using a broken compiler. You should consider updating. Even if the standard didn't explicitly outlaw that definition, it would still be invalid: implicit conversion from void* to other pointer types is not allowed.
Quote:

The truth is it doesn't matter what the C++ spec says, it all depends on what you actually need. Not to sound pessimistic but the truth is that to develop for all architectures is essentially impossible, since the various querks even in the compilers would make program maintenence a nightmare and not engineeringly 'sane'.

While true, you can go a long way by avoiding things that are obviously unsafe in favor of nice, well defined constructs. Using default constructors instead of memset isn't exactly bending over backwards for compatability purposes.

CM

Share this post


Link to post
Share on other sites
Quote:
Original post by V-man
Really, is this something you need to worry about?


When I started programming in C++, I had about the same reaction as you. I read about alignment, and thought to myself: what the hell! Any modern processor can read misaligned fields without a problem, so why bother handling alignment at all?

And so several of my personal libraries did not handle alignment at all — the performance loss was negligible but I had much less work to do.

Then, I ported my code to the PocketPC. Oh, woe was me, the ARM processor did not handle misaligned fields as smoothly as the x86 did: it choked, gagged and died a colourful death every single time, forcing me to reset the device. I had to rewrite large portions of code to accomodate with alignment, and it was pretty nasty.

So yes, abiding by the standard is a pretty good thing to do.

Share this post


Link to post
Share on other sites
Quote:
Original post by Krysole
The truth is it doesn't matter what the C++ spec says


Statements like this always get under my skin... *ick*

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
Quote:
Original post by V-man
Really, is this something you need to worry about?


When I started programming in C++, I had about the same reaction as you. I read about alignment, and thought to myself: what the hell! Any modern processor can read misaligned fields without a problem, so why bother handling alignment at all?

And so several of my personal libraries did not handle alignment at all — the performance loss was negligible but I had much less work to do.

Then, I ported my code to the PocketPC. Oh, woe was me, the ARM processor did not handle misaligned fields as smoothly as the x86 did: it choked, gagged and died a colourful death every single time, forcing me to reset the device. I had to rewrite large portions of code to accomodate with alignment, and it was pretty nasty.

So yes, abiding by the standard is a pretty good thing to do.


Well yes, if you are targeting a platform that has a particular need like memory accesses that are multiple of 32 bit or something, then write specific code for it.

I'm all for performance. I love performance.

But NULL beeing defined differently on ancient CPUs.... who cares.

I like using memset and memcpy and do various pointer to pointer casts and pointer to integer casts. I can do useful things in C++ that is not possible with Ultra-OO languages like Java, C#, VB.NET



Share this post


Link to post
Share on other sites
Quote:

I like using memset and memcpy and do various pointer to pointer casts and pointer to integer casts. I can do useful things in C++ that is not possible with Ultra-OO languages like Java, C#, VB.NET


Kind of makes me wonder what other realms of undefined behavior you've entered without knowing it...

Perhaps statements like "it doesn't matter what the standard says," and "who cares about machines with weird architecture" are...excusable (if, in my opinion, idiotic) for hobby developers who will realisticly never be targeting more than one platform. But anyone who has ambitions of becoming a professional software developer in any industry had best be aware of what is, and is not, strictly legal or otherwise constitutes "shady behavior" (hacks) in their languages of choice.

I cannot recall how many times I have had to find and fix bugs relating to the fallthrough of architectural assumptions or assumptions that "hey, it's not standard, but it works on our machines with our compilers so it must work on others!"

Share this post


Link to post
Share on other sites
Quote:
I like using memset and memcpy and do various pointer to pointer casts and pointer to integer casts. I can do useful things in C++ that is not possible with Ultra-OO languages like Java, C#, VB.NET


Software Company A:
We've built your software project. It respects the latest standard of language FOO, widely-known development methodologies BAR and is certified as safe and correct by static analysis tool BAZ.


Software Company B:
We've built your software project. We've done some really clever tricks which we're pretty sure would work on a certain set of machines (at least, those we have heard of lately), but we can't be sure because we didn't respect the FOO language standard so your compiler might choke on the code. Besides, we've given up on proven development methodologies BAR, so the program may be difficult to maintain or extend, but that's no problem, right? It does really use some clever useful tricks that we couldn't have used without a little additional effort if we had used the BAR methodology. Now that you mention it, maybe these tricks wouldn't have been useful had we used BAR, but never mind, they're clever. Oh, and because of these clever tricks, static analysis tool BAZ just won't accept that our program is safe (darned thing keeps mentioning non-portability warnings), but you can believe us when we say it is safe. Warranties? You don't need no warranties, no sir.


Conclusion: being proud of clever non-standard tricks with undefined behaviour makes you sound like an amateur used car salesman, not like a professional software developer. Side-effects may include your successes being attributed to sheer luck, and your advice in general being ignored or scorned.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this