When the token 0 appears in the source code at a place where a pointer should be, the compiler interprets the token 0 as the NULL pointer. However, the bit pattern for the NULL pointer is not guaranteed to be all zeros. More specifically, setting a pointer to NULL may set some of the bits of that pointer to 1. Depending on the hardware, the operating system, or the compiler, a pointer whose bits are all zeros may not be the same as the NULL pointer. For example, using memset() to set all the bits of a pointer to zero may not make that pointer equal to NULL. In the following program, all conforming C++ compilers produce code that prints 0 is NULL, then NULL is NULL, but some may produce code that prints memsetPtr is not NULL. #include <iostream> #include <string> using namespace std; void checkForNull(const string& nameOfPointer, char* p) { cout << nameOfPointer; if (p == NULL) cout << " is NULL\n"; else cout << " is not NULL\n"; } int main() { checkForNull("0", 0); <-- 1 checkForNull("NULL", NULL); <-- 2 char* memsetPtr; memset(&memsetPtr, '\0', sizeof(memsetPtr)); <-- 3 checkForNull("memsetPtr", memsetPtr); }
Another common way to generate a pointer whose bits are all zero that is equally dangerous is with unions. For example, the following is wrong on two levels. First, it accesses the char* member of the union even though it was the unsigned long member that was set most recently. Second, it assumes that a pointer whose bits are all zero is the same as a NULL pointer the output may be unionPtr is not NULL on some machines. union Fred { unsigned long n; char* p; }; void badForm() { Fred x; x.n = 0; <-- 1 char* unionPtr = x.p; <-- 2 checkForNull("unionPtr", unionPtr); }
|