是否需要将NULL转换为结构指针类型以便在C中进行赋值/比较?

时间:2012-05-09 05:26:00

标签: c pointers struct null

我的老师不断将 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

6 个答案:

答案 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)

这个问题的正确答案是你的老师没有错误,他/她也不是无知。他/她只是在教你良好的习惯。使用显式强制转换不是必须的,但至少有两个很好的理由可以解释为什么。

  1. 代码可移植性

    使用显式广播功能可确保您的代码之间的代码可移植 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>
  2. 代码可读性

    使用显式转换可以极大地提高可读性。例如,根据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文档。这使代码自我 记录,如果您处于众多非图形环境之一,这一点尤为重要 没有内置代码浏览支持。

  3. 在ANSI C99(ISO / IEC 9899:1999,第6.5.16.1节)中,ANSI同意 NULL指针常量的概念,并将NULL指针常量赋值给指针打字的对象是合法的。

    然而,老师教你上述方法的真正原因是因为他/她只是像任何好老师一样为现实世界做准备,而在现实世界中,ANSI C标准不是法律。不必遵循它,并且在大多数情况下不遵循它。如果要获得财务利润或市场份额,编译器公司会忽略或扩展任何标准。此外,还有很多的专有计算机系统,其中一些是世界上最大的制造商,其中安装了非ANSI C兼容的编译器,并且用于编译C程序,因为它们必须支持非标准硬件。

    这就是为什么在执行涉及NULL的任何指针操作时使用显式强制转换是一个非常好的习惯。它将确保您的代码可以快速理解,编译干净,并且可以在以后生活中遇到的各种平台和编译器工具中按预期工作。