正如comp.lang.c常见问题所述,有一些架构,其中空指针不是所有位零.所以问题是实际检查以下结构:
void* p = get_some_pointer();
if (!p)
return;
Run Code Online (Sandbox Code Playgroud)
我是否p与机器相关的空指针进行比较或者我是否p与算术零进行比较?
我应该写
void* p = get_some_pointer();
if (NULL == p)
return;
Run Code Online (Sandbox Code Playgroud)
相反,为这样的架构做好准备还是仅仅是我的偏执?
我一直认为只会if(p != NULL){..}做这项工作.但在阅读Stack Overflow问题后,似乎没有.
那么在吸收了那个说明NULL指针可能具有非零值的问题的所有讨论之后检查NULL指针的规范方法是什么?
我问,因为在这个帖子中引发了讨论.
尝试在其他人的回复下使用评论进行严肃的来回讨论并不容易或有趣.所以我想听听我们的C专家的想法,一次不限制500个字符.
C标准几乎没有什么可说的NULL和空指针常量.我只能找到两个相关部分.第一:
3.2.2.3指针
具有值0的整型常量表达式,或者类型为void*的表达式,称为空指针常量.如果为指针的相等性分配或比较空指针常量,则将常量转换为该类型的指针.这种称为空指针的指针保证与指向任何对象或函数的指针不相等.
第二个:
4.1.5通用定义
宏是
Run Code Online (Sandbox Code Playgroud)NULL它扩展为实现定义的空指针常量;
问题是,可以NULL扩展为实现定义的空指针常量,该常量与3.2.2.3中列举的那些不同吗?
特别是,它可以定义为:
#define NULL __builtin_magic_null_pointer
Run Code Online (Sandbox Code Playgroud)
甚至:
#define NULL ((void*)-1)
Run Code Online (Sandbox Code Playgroud)
我对3.2.2.3的解释是,它指定0的整数常量表达式和0强制转换为类型void*的整型常量表达式必须是实现可识别的空指针常量的形式,但它不是意思是一份详尽的清单.我相信实现可以自由地将其他源构造识别为空指针常量,只要没有其他规则被破坏.
例如,可以证明这一点
#define NULL (-1)
Run Code Online (Sandbox Code Playgroud)
不是法律定义,因为在
if (NULL)
do_stuff();
Run Code Online (Sandbox Code Playgroud)
do_stuff() 不能被称为,而与
if (-1)
do_stuff();
Run Code Online (Sandbox Code Playgroud)
do_stuff()必须被召唤; 因为它们是等价的,所以这不是法律定义NULL.
但是标准说整数到指针的转换(反之亦然)是实现定义的,因此它可以定义-1到指针的转换,作为产生空指针的转换.在这种情况下
if ((void*)-1)
Run Code Online (Sandbox Code Playgroud)
会评价为假,一切都会好的.
那么别人怎么想呢?
我要求每个人特别记住中描述的"假设"规则2.1.2.3 Program execution.它是巨大的,有点迂回,所以我不会在这里粘贴它,但它实质上说,一个实现只需要产生与标准描述的抽象机器所需的相同的可观察副作用.它表示,只要程序的可观察副作用不被它们改变,任何优化,转换或编译器想要对程序执行的任何其他操作都是完全合法的.
因此,如果您希望证明特定的定义NULL不合法,您需要提出一个可以证明它的程序.任何一个像我一样公然打破标准中的其他条款,或者可以合法地检测编译器必须做的任何魔法来使奇怪的NULL定义工作.
Steve Jessop发现了一个程序检测方法的例子,NULL它没有被定义为3.2.2.3中两种形式的空指针常量之一,它是将常量字符串化:
#define stringize_helper(x) #x
#define stringize(x) stringize_helper(x)
Run Code Online (Sandbox Code Playgroud)
使用这个宏,人们可以
puts(stringize(NULL));
Run Code Online (Sandbox Code Playgroud)
并"检测"NULL不会扩展到3.2.2.3中的一个表单.这足以使其他定义非法吗?我只是不知道.
谢谢!
可能重复:
C中的NULL总是为零?
C标准规定了以下内容calloc():
calloc函数为nmemb对象数组分配空间,每个对象的大小都是size.空间初始化为所有位零.
以下有关所有位零的警告:
注意,这不必与浮点零或空指针常量的表示相同.
测试程序:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
char** list = calloc(10, sizeof(*list));
int i;
for (i = 0; i < 10; i++)
{
printf("%p is-null=%d\n", list[i], NULL == list[i]);
}
free(list);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我用以下编译器构建并执行了这个程序:
在所有情况下,所有位零都是NULL指针(除非我在测试程序中犯了错误).
是什么原因NULL导致C标准不能保证指针是零位?出于好奇,是否有任何编译器所有位零都不是NULL指针?
我们有一个用C编写的代码,有时候不能很好地处理零指针.
代码最初是在Solaris上编写的,这样的指针会导致分段错误.不理想,但比耕作更好.
我们的经验是,如果从AIX上的空指针读取,则得到0.如果使用xlc编译器,则可以添加一个选项-qcheck=all来捕获这些指针.但我们使用gcc(并希望继续使用该编译器).请问GCC提供这样的选择?
我想连接两个定义如下的字符串:
char hello[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
char world[] = { ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\0' };
Run Code Online (Sandbox Code Playgroud)
我明白我应该跑过第一个,找到'\0'标志而不是它开始第二个字符串.功能是否strcat以相同的方式工作?
我正在使用的代码:
for (int i = 0; i < 6; i++) {
if (hello[i] == '\0') {
for (int j = 0; j < 9; j++) {
int index = 5 + j;
hello[index] = world[j];
}
}
}
Run Code Online (Sandbox Code Playgroud)
编译后我得到这样一个错误:
*堆栈粉碎检测到*:./ run终止
我究竟做错了什么?