在C(或C++)中,指针是特殊的,如果它们的值为零:我建议在释放内存后将指针设置为零,因为这意味着再次释放指针并不危险; 当我调用malloc时,如果它无法获取内存,则返回一个值为零的指针; 我一直用if (p != 0)它来确保传递的指针是有效的,等等.
但是,由于内存寻址从0开始,因此有效地址不是0吗?如果是这样的话,0如何用于处理空指针?为什么不是负数而是null?
编辑:
一堆好的答案.我将总结在所表达的答案中所说的内容,因为我自己的思想解释了它,并希望如果我误解,社区将纠正我.
就像编程中的其他一切一样,它是一种抽象.只是一个常量,与地址0并不真正相关.C++ 0x通过添加关键字来强调这一点nullptr.
它甚至不是地址抽象,它是C标准指定的常量,只要它确保它永远不等于"真实"地址,编译器就可以将它转换为其他数字,如果0不是,则等于其他空指针用于平台的最佳价值.
如果它不是抽象,早期就是这种情况,系统使用地址0,程序员不受限制.
我承认,我的负面数字建议是一个狂热的头脑风暴.对地址使用有符号整数有点浪费,如果它意味着除了空指针(-1或其他)之外,值空间在产生有效地址的正整数和刚刚浪费的负数之间均匀分配.
如果任何数字总是可以由数据类型表示,那么它就是0.(也可能是1.我想的是一位整数,如果是无符号则为0或1,或者只有符号的有符号位,或两位整数,将是[-2,1].但是你可以只得0为空,1是内存中唯一可访问的字节.)
还有一些东西在我的脑海里没有得到解决.Stack Overflow问题指向特定固定地址的指针告诉我,即使0表示空指针是抽象,其他指针值也不一定.这导致我发布另一个Stack Overflow问题,我是否可以访问地址零?.
在C中,NULL定义为(void *)0在C++中它是0.为什么会这样?在CI中可以理解,如果NULL不是类型转换,(void *)则编译器可能/可能不会生成警告.除此之外,有什么理由吗?
在针对C++ 11的SO上回答这个问题的过程中,我意识到在C++ 03(以及C)中,在常量表达式中明确禁止使用逗号运算符.
关于常量表达式的C++ 03标准的第5.19/1段说:
[...]特别是,除了sizeof表达式,不应使用函数,类对象,指针或引用,并且不得使用赋值,递增,递减,函数调用或逗号运算符.
但是,在C++ 11中,提到逗号运算符的最后一部分似乎已经消失了.虽然C++ 11标准的第5.19/2段明确规定赋值,递增,递减和非constexpr函数调用表达式不应作为常量表达式的子表达式出现,但逗号运算符的使用似乎不一致被禁止了.
例如,以下程序在GCC 4.7.2和Clang 3.3上编译良好std=c++11(除了编译器警告说逗号运算符没有效果且x和arr变量未使用):
int main()
{
constexpr int x = (0, 42);
int arr[(0, 42)];
}
Run Code Online (Sandbox Code Playgroud)
但是,必须要说的是,即使是以下程序也可以使用-std=c++03选项(在Clang和GCC上)编译好,这显然是不正确的,考虑到C++ 03标准的上述引用:
int main()
{
int arr[(0, 42)];
}
Run Code Online (Sandbox Code Playgroud)
题:
关于逗号运算符是否允许在常量表达式中,或者我是否遗漏了某些内容,C++ 03和C++ 11之间是否存在差异?
作为一个奖励(非建设性)问题,我有兴趣知道为什么逗号运算符不能用在C++ 03中的常量表达式中.
c++ comma-operator language-lawyer constant-expression c++11
这可以被认为是这个问题的扩展(我只对C感兴趣,但添加C++来完成扩展)
6.3.2.3.3中的C11标准说:
值为0的整型常量表达式或此类表达式转换为类型
void *称为空指针常量.
我个人对此的看法是0并且(void *)0表示空指针,其整数值实际上可能不是0,但是不包括0强制转换为任何其他类型.
但是,标准然后继续:
如果将空指针常量转换为指针类型,则生成的指针称为空指针,...
它包含(int *)0为空指针,因为强制转换是一种显式转换(C11,6.3),它在转换方法下列出.
然而,令我惊讶的是以下短语
...或者这样的表达式转换为
void *...
有了上面的语义,这句话似乎完全没用.问题是,这句话完全没用吗?如果没有,它有什么影响?因此,是否(int *)0为空指针?
另一个可以帮助讨论的问题如下.被(long long)123视为"123转换为long long",或"123与类型long long".换句话说,有没有转换(long long)123?如果没有,则上面的第二个引用不包括(int *)0为空指针.
阅读这个 Q&A,我认为p不应该是一个nullptr即使x是0.我明白了吗?
int main()
{
int x = 0;
std::cin >> x; // Enter `0`
void *p = (void *)x; // or: void *p = reinterpret_cast<void*>(x);
if (!p)
std::cout << "p is nullptr" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
输入0标准输入后,该消息p is nullptr将显示在我的GCC中.根据链接,它不应该评估nullptr,但结果不是我的期望.
代码是否未定义行为?或未指明的结果?为什么要评估nullptr?