显然在包含的文件中未知NULL

时间:2018-12-21 14:21:38

标签: c gcc c-preprocessor

我面临一个奇怪的问题:

我的主要开始是:

#include <stdlib.h>     /* this defines NULL */
#include <stdio.h>      /* ditto */
#include <fcntl.h>
#include <ctype.h>      /* ditto */
#include <unistd.h>     /* ditto */

#include <linux/input.h>

#include <string.h>     /* ditto */
#include <sys/ioctl.h>

#include "parse.h"

...但是在包含的文件中:

#define NULL ((void*)0)  /* I need this! */

struct parse_key {
    char *name;
    unsigned int value;
} keynames[] = {
    {"KEY_RESERVED", 0},
    {"KEY_ESC", 1},
    {"KEY_1", 2},
    {"KEY_2", 3},
    ...
    {"KEY_MAX", 0x2ff},
    {NULL, 0}
};

我需要重新定义NULL,否则会出现错误:“错误:此处未声明“ NULL”(不在函数中)”。

注意:NULL 在主文件中定义;如果我尝试#define,它将得到:“警告:“ NULL”重新定义“

修复很简单,但是我不知道发生了什么。有人可以照亮吗?

5 个答案:

答案 0 :(得分:6)

请勿重新定义。

只需在头文件中包含<stdlib.h>

也不要在头文件中定义任何功能和数据。如果在许多C文件中使用了类型声明,外部变量,函数声明和静态内联函数,则只有它们。

答案 1 :(得分:5)

通常,当您在实际的头文件中未包含必需的头文件时,就会发生此问题,但是在某些编译单元中,它们会被包含在头文件之前。

即您的头文件没有必要的#include

// parse.h
#ifndef PARSE_H
#define PARSE_H

struct parse_key
{
    char *name;
    unsigned int value;
}

static inline void key_init(struct parse_key * pk)
{
    pk->name = NULL; // <-- you need it here
}

#endif // PARSE_H

然后您有两个编译单元,但是其中只有一个包含适当的头文件:

// something.c
#include <stdlib.h>
#include "parse.h"    // <-- preprocessor inserts this when NULL is already known


// something_else.c
#include "parse.h"    // <-- but in this case, it will not compile

唯一可靠的解决方案是将所有必需的标头包含在有问题的标头本身中。

由于仅编译.c文件,因此如果缺少.h文件中的包含内容,编译器将不会在意,但是在这种情况下,Visual Studio或Eclipse之类的IDE经常显示警告消息。

作为旁注,

struct parse_key {
    char *name;
    unsigned int value;
} keynames[] = {
    {"KEY_RESERVED", 0},
    {"KEY_ESC", 1},
    {"KEY_1", 2},
    {"KEY_2", 3},
    ...
    {"KEY_MAX", 0x2ff},
    {NULL, 0}
};

是一个变量,它将在包含头文件的每个编译单元中创建。这意味着您可能还会收到链接器错误,告诉您变量重复。

答案 2 :(得分:0)

我同意先前的回答,但尝试解释您的问题:

如果您#include stdlib.h 然后 parse.h,其中(重新)定义了NULL,则您将得到重新定义,因为在stdlib中已经定义了NULL

如果在其他文件中,您#include parse.h 但不是 stdlib.h,则需要在parse.h中定义NULL,否则未定义

如果您真的想在parse.h中使用NULL,则需要在其中#include stdlib,但对我而言,最好的方法是不使用NULL

答案 3 :(得分:0)

此处的宏重新定义不正确。 <li class="active"><a href="#">2</a></li>是这些标头保留的名称,在包含定义标头的标头之前定义它会调用未定义的行为。

最好在自己的标头中包含所需的 minimum 标头。

如果只需要NULL和诸如NULL之类的类型,请仅包含 <stddef.h>

答案 4 :(得分:0)

NULL在<stddef.h>库中定义。