在C和C++中,NULL/false代表的不仅仅是0x0 / 0b0 / '\0' / 0。
在C和C++中,NULL表示一个空指针。一个被声明为NULL的指针不能被引用,只能被赋予其他值。而0或者0x0可以是一个指针的值,既可以被引用也可以被赋值。
为什么会出现NULL和0的区别呢?这是因为在C和C++中,NULL被定义为0,但它的含义更为广泛。NULL不仅仅表示0,还表示一个指针指向的地址不存在或者未初始化。因此,当一个指针被赋值为NULL时,我们可以确定它没有有效的地址。
然而,0或者0x0可以是一个指针的合法值,表示指针指向的是一个有效的地址。这意味着我们可以对这样的指针进行引用和赋值操作。
那么如何解决这个问题呢?当我们需要判断一个指针是否为空时,应该使用NULL而不是0。因为NULL更准确地表示一个指针没有有效的地址。另外,在进行指针的比较操作时,也应该使用NULL而不是0,以避免歧义。
总结起来,NULL表示一个空指针,表示一个指针没有有效的地址;而0或者0x0可以是一个指针的值,表示指针指向的是一个有效的地址。为了正确地判断一个指针是否为空,以及避免歧义,我们应该使用NULL而不是0。
在C和C++中,NULL被保证为零,可能被转换为(void *)1。
根据C99,§6.3.2.3, ¶3规定:
整数常量表达式的值为0,或者将这样的表达式转换为类型void *,被称为空指针常量。如果将空指针常量转换为指针类型,得到的指针称为空指针,保证与任何对象或函数的指针比较不相等。
注意到,因为空指针的规则如何制定,您用于赋值/比较空指针的值保证为零,但实际存储在指针内部的位模式可以是任何其他值(但据我所知,只有少数非常奇特的平台利用了这一事实,而且这应该不是一个问题,因为要"看到"底层位模式,您应该进入未定义行为的领域)。
因此,就标准而言,这两种形式是等价的(由于§6.5.3.3 ¶5,!ptr等效于ptr==0,ptr==0等效于ptr==NULL);if(!ptr)也是相当惯用的写法。
话虽如此,我通常会明确地写成if(ptr==NULL)而不是if(!ptr),以便更清楚地检查指针是否为空,而不是某个布尔值。
需要注意的是,在C++中,由于更严格的隐式转换规则,不能出现void *转换的情况,否则使用这样的NULL会很麻烦(每次都必须显式将其转换为比较指针的类型)。
您可以通过使用char*查看指针并读取其字节来查看底层位。然而,这些字节和位的含义是完全未指定的。
在C和C++中,NULL/false的值并不一定是0x0、0b0、'\0'或者0。这是由于不同的平台可能有不同的定义。以下是一些非零NULL值的例子。
虽然空指针的地址可能不是数值0,但是数值为0的整数常量仍然会被转换为空指针。
出现这个问题的原因是,不同的平台对于空指针的定义可能不同,导致NULL/false的值并非一定是0x0、0b0、'\0'或者0。
解决这个问题的方法是,不要通过比较NULL/false的数值来判断空指针,而应该使用特定的空指针判断语法。例如,在C中可以使用if(ptr == NULL)来判断指针是否为空,在C++中可以使用if(ptr == nullptr)来判断指针是否为空。
以下是一些示例代码,展示了如何正确地判断空指针:
#includeint main() { int* ptr = NULL; if (ptr == NULL) { printf("ptr is a null pointer\n"); } else { printf("ptr is not a null pointer\n"); } return 0; }
#includeint main() { int* ptr = nullptr; if (ptr == nullptr) { std::cout << "ptr is a null pointer" << std::endl; } else { std::cout << "ptr is not a null pointer" << std::endl; } return 0; }
通过使用特定的空指针判断语法,我们可以确保在不同的平台上都能正确地判断空指针。这样可以避免因为NULL/false的值不是0而导致的错误判断。