Home Page
  • October 09, 2024, 12:38:00 am *
  • Welcome, Guest
Please login or register.

Login with username, password and session length
Advanced search  

News:

Official site launch very soon, hurrah!


Author Topic: NULL Pointer for C++  (Read 12458 times)

Dakusan

  • Programmer Person
  • Administrator
  • Hero Member
  • *****
  • Posts: 544
    • View Profile
    • Dakusan's Domain
NULL Pointer for C++
« on: September 28, 2009, 05:32:25 am »

Original post for NULL Pointer for C++ can be found at https://www.castledragmire.com/Posts/NULL_Pointer_for_C%2B%2B.
Originally posted on: 06/17/09

I’ve recently been frustrated by the fact that NULL in C++ is actually evaluated as integral 0 instead of a pointer with the value of 0. This problem can be seen in the following example:


class String
{
   String(int i)  { /* ... */ } //Convert a number to a string
   String(char* i){ /* ... */ } //Copy a char* string directly into the class
};

String Foo(NULL); //This would give the string "Foo" the value "0" instead of a char* to (void*)0

The solution I came up with, which my good friend Will Erickson (aka Sarev0k) helped me revise, is as follows:


#undef NULL //If NULL is already defined, get rid of it
struct NULL_STRUCT { template <typename T> operator T*() { return (T*)0; } }; //NULL_STRUCT will return 0 to any pointer
static NULL_STRUCT NULL; //NULL is of type NULL_STRUCT and static (local to the current file)

After coming up with this way of doing it, I found out this concept is already a part of the new C++0x standard as nullptr, but since it is not really out yet, I still need a solution for the current C++ standard.


After getting this to work how I wanted it, I tested it out to make sure it is optimized correctly in compilers. When the compiler knows a value will be 0, it can apply lots of special assembly tricks.

Microsoft Visual C++ got it right by seeing that NULL was just 0 and applying appropriate optimizations, but GCC missed an optimization step and didn’t detect that it was 0 down the whole pipe. GCC, to my knowledge, however, isn’t exactly known for its optimization.


Example code:

BYTE* a=...; //Set a to an arbitrary value (best if brought in via an external method [i.e. stdin] so the compiler doesn’t make assumptions about the variable)
bool b=(a==NULL); //Set to b if a is 0 (NULL)
What MSVC6 outputs (and what it should be after optimization):

test eax,eax   //logical and a against itself to determine if it is 0 or not
sete al      //Set the lowest byte of eax to 1 if a is 0
What GCC gives

xor edx,edx   //Temporarily store 0 in edx for later comparison. This is a 0 trick, but 1 step higher than it could be used at.
cmp edx,eax   //Compare a against edx (0)
sete al      //Set the lowest byte of eax to 1 if a equals the value in edx

On a side note, it has been quite painful going from using assembly in Microsoft Visual C++ to GCC for 2 reasons:
  • I hate AT&T (as opposed to Intel) assembly syntax. It is rather clunky to use, and every program I’ve ever used is in Intel syntax (including all the Intel reference documentation). I tried turning on Intel syntax through a flag when compiling through GCC, but it broke GCC. :-\
  • Having to list which assembly registers are modified/used in the extended assembly syntax. This interface is also very clunky and, I have found, prone to bugs and problems.
Logged