我的老师不断将 NULL 转换为(struct foo *),然后再将其指向结构foo的指针。例如:
struct foo {
// smthg else
struct foo *ptr;
};
struct foo *bar;
bar = (struct foo*)malloc(sizeof(struct foo));
bar->ptr = (struct foo *) NULL;
令我难以置信的是,他唯一一次测试该值是否为NULL(检查链表是否已经结束)他执行以下操作
if (aux->ptr != (struct foo *) NULL) {
...
}
我问他为什么,如果要“增长”NULL的大小以防止错误或其他什么。但不,他告诉我(非常不情愿,我认为)这是为了防止编译器出现一些可能的错误(wtf?)。 这真的有必要吗?
修改
他所教的语言是C.他可能不知道在C中投射malloc是不必要的。我想知道他是否只是小心或无能。 :P
答案 0 :(得分:7)
回答你的问题:不,没有必要将NULL
强制转换为特定的指针类型。编译器为NULL
提供了一个特殊情况,并允许将其分配给任何指针类型,而不指示指针类型转换警告。
同样,在与NULL
进行比较时,没有必要进行投射:
if (aux->ptr != NULL) {
答案 1 :(得分:4)
的正确形式
struct foo *bar = (struct foo*)malloc(sizeof(struct foo));
C中的总是
struct foo *bar = malloc(sizeof *bar);
你的教授是错的,并且在尝试使用C ++中的malloc
时可能会养成不良习惯(这通常是不赞成的,有充分的理由)。
答案 2 :(得分:1)
在C中,malloc
的结果不需要转换为变量类型。在C ++中,它必须是,否则你将得到一个编译时错误(不能隐式地将void *
转换为your_class *
)。
如果您的老师试图教您正确的编码原则,则需要演员。如果您的老师正在尝试教您C语言准备C ++,则需要学习使用演员表。对于老师说“为了防止编译器出现一些可能的错误”,没有什么“wtf” - 你应该更经常地听取他的意见。假设你的教授无知,可能不是你要走的路。
答案 3 :(得分:1)
没有必要将NULL转换为特定的指针类型,因为NULL是#defined为0.我能想到的唯一原因是教育,因为你可以很好地记住对象和指针的类型写你的程序。
在C ++中,您将使用nullptr进行初始化并使用g ++ -std = c ++ 0x
进行编译最后,有必要在C ++中转换malloc的返回值,而不是在C中。在C ++中,你应该使用'new'。
答案 4 :(得分:1)
曾经有过#define NULL 0
的错误编译器,并且0不是(C89)C标准所要求的空指针常量。现在,你不太可能遇到这样的编译器。
它曾经在诸如execl("cmd", "arg0", "arg1", NULL);
之类的上下文中起作用,因为NULL需要是一个空指针常量,但是......现在,NULL是一个空指针常量,因此强制转换为真的不是甚至必要。对于赋值操作,您只需编写0
而不是强制转换NULL。在execl()
示例中,您不能只写0;这是一个int
,不一定是空指针常量。
答案 5 :(得分:-2)
这个问题的正确答案是你的老师没有错误,他/她也不是无知。他/她只是在教你良好的习惯。使用显式强制转换不是必须的,但至少有两个很好的理由可以解释为什么。
代码可移植性
使用显式广播功能可确保您的代码之间的代码可移植 ANSI C编译器,ANSI前编译器,最重要的是非ANSI 符合C标准的编译器。你老师的代码不应该生成 任何编译器的错误或警告,符合或不符合, 过去,现在或将来。
如果在任何早于ANSI C或不是ANSI的平台上进行编译 兼容,编写代码:
pMyObject = NULL;在某些系统上,
可以生成编译器警告:
warning: '=' conversion from 'void*' to 'struct foo*' warning: '=' conversion from 'int' to 'struct foo*'
编译器警告的目的是提醒您潜在的问题,因此,即使单个警告编译的代码也不应被视为生产质量代码,除非通过显式强制转换修复警告。
< / LI>代码可读性
使用显式转换可以极大地提高可读性。例如,根据Microsoft Windows SDK:
采用以下真实示例hMyWindow = CreateWindow(NULL, NULL, WM_OVERLAPPED, 0, 0, 100, 100, NULL, NULL, NULL, NULL); if (hMyWindow == NULL) ...
除非您参考Microsoft Windows SDK,否则很明显您将无法理解传递给此函数的参数。但是,如果我写:
hMyWindow = CreateWindow((LPCTSTR) NULL, (LPCTSTR) NULL, WM_OVERLAPPED, 0, 0, 100, 100, (HWND) NULL, (HMENU) NULL, (HINSTANCE) NULL, (LPVOID) NULL); if (hMyWindow == (HWND) NULL) ...
然后我知道,在瞬间:1)变量类型hWindow
,2)返回CreateWindow()
的类型,3)每个函数参数的类型。几乎我需要知道的一切,以了解这些代码,我不必扫描当前文件,或寻找另一个头文件,或浪费时间浏览互联网寻找API文档。这使代码自我
记录,如果您处于众多非图形环境之一,这一点尤为重要
没有内置代码浏览支持。
在ANSI C99(ISO / IEC 9899:1999,第6.5.16.1节)中,ANSI同意 NULL指针常量的概念,并将NULL指针常量赋值给指针打字的对象是合法的。
然而,老师教你上述方法的真正原因是因为他/她只是像任何好老师一样为现实世界做准备,而在现实世界中,ANSI C标准不是法律。不必遵循它,并且在大多数情况下不遵循它。如果要获得财务利润或市场份额,编译器公司会忽略或扩展任何标准。此外,还有很多的专有计算机系统,其中一些是世界上最大的制造商,其中安装了非ANSI C兼容的编译器,并且用于编译C程序,因为它们必须支持非标准硬件。
这就是为什么在执行涉及NULL
的任何指针操作时使用显式强制转换是一个非常好的习惯。它将确保您的代码可以快速理解,编译干净,并且可以在以后生活中遇到的各种平台和编译器工具中按预期工作。