3

我正在尝试创建一个头文件(其中将包括我为 AVL 树编写的函数),但我对包含保护的语法有一个小问题和误解。

现在我的代码看起来像这样

#ifndef STDIO_H
#define STDIO_H
#endif
#ifndef STDLIB_H
#define STDLIB_H
#endif
#ifndef CONIO_H
#define CONIO_H
#endif

问题是,我认为它只包括<stdio.h>. 当我尝试使用 malloc 时,它说 malloc 未定义,即使我包含了 stdlib。

根据http://www.cprogramming.com/reference/preprocessor/ifndef.html,如果我理解正确,ifndef 检查令牌是否已定义,如果未定义,它定义我在 ifndef 之后和#endif 之前编写的所有内容。所以我的代码应该可以工作。

是否定义了 stdio?不。所以定义它。万一。定义了标准库吗?不。所以定义它。万一。conio 定义了吗?不。所以定义它。万一。我没有看到问题。

如果我想添加这 3 个标题,正确的语法是什么?

4

5 回答 5

7

包含保护用于防止包含文件被多次包含的情况下的双重定义。

标准包含文件具有必要的包含保护,因此您不需要包含保护。

您的代码应该是:

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
于 2014-08-18T10:37:53.770 回答
2

以下声明将不包含您的stdio.h标题。

#ifndef STDIO_H
#define STDIO_H
#endif

如果您这样声明,并不意味着它将包含您的stdio.h头文件。它最适合“自己的标题”。

您需要在您自己的头文件(avltree.h)文件中包含所有声明和函数定义,如下所示 -

#ifndef AVLTREE_H
#define AVLTREE_H

/* YOUR HEADER FILE STUFF */

#endif

然后将该头文件包含在您的主程序中。

stdio.hstdlib.h并且conio.h已经是可用的头文件,可以直接将所有文件包含在主程序文件中——

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
于 2014-08-18T10:37:24.327 回答
1

您将包含守卫放在自己的标题中。

如:

//GameEntity.hpp
#ifndef __H_GAME_ENTITY
#define __H_GAME_ENTITY

class GameEntity{
  //whatever
};

#endif

然后它将只包含一次到编译单元中。

现在这样的事情不会失败:

#include <GameEntity.hpp>
#include <GameEntity.hpp>

int main(){ return 0; };
于 2014-08-18T10:39:46.647 回答
0

添加这 3 个标头的正确语法是:

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

是一个预#ifndef处理器指令,后面跟着一个标记,让它成为X。它将检查是否X已通过#define预处理器指令定义,如果没有,则后续行将由您的编译器处理,直到对应的#endif. 例如;

// #define X
// #define X 123456

#ifndef X
/* some code */
#endif

上面的内容可以理解为X 未定义/* some code */仅当X未定义时才考虑该部分,在这种情况下,未定义X,所以它会。如果我取消注释上述任何一个,编译器将忽略#define ...该部分。/* some code */

包含保护是利用我上面解释过的这个东西的东西#ifndef。您不必担心这些,直到您为自己制作头文件。

头文件通常(通常)在自己内部有#include guards。无论他们做什么,他们首先检查是否已经定义了某个特定的令牌。如果没有,那么他们将自己定义该令牌并做任何事情。如果它已经被定义,那么他们什么也不做。这是为了防止对内部任何内容进行不必要的多重定义。例如,如果您要检查<stdio.h>MSVC 2013,您会看到它的开头和结尾如下:

#ifndef _INC_STDIO
#define _INC_STDIO

// hundreds of lines in between

#endif

多亏了这一点,如果您要编写如下内容:

#include <stdio.h>
#include <stdio.h>

// ...

在您的代码中,第二个#include几乎什么都不做,因为第一个已经执行了 line #define _INC_STDIO,它定义_INC_STDIO并阻止了几乎所有内容在<stdio.h>后续包含中再次执行。

这并不是为了防止对不起,程序员的“愚蠢”错误,当一个头文件包含另一个头文件本身时,它很有用。例如,在 MSVC 2013 中,两者都<stdio.h>尝试<stdlib.h>将其包含<crtdefs.h>为他们的第一个操作。现在,如果<crtdefs.h>包含两次,里面的一堆类型定义将被多次定义,而它们不应该。当然,我可以在我的代码之上写下以下内容:

#include <stdio.h>
#include <stdlib.h>

// ...

#include守卫会为我节省一天的时间,防止内容被<crtdefs.h>多次执行。

于 2014-08-18T10:55:34.967 回答
-1

正如之前的评论和每个人都指出的那样,您没有在主头文件中包含任何内容。

即使我也准备了单个头文件,我更喜欢这样做:

假设您有一个主头文件“includes.h”,其中包含所有头文件。然后

#ifndef INCLUDES_H
#define INCLUDES_H

#ifndef STDIO_H
     #include <stdio.h>
#endif

#ifndef STDLIB_H
     #include <stdlib.h>
#endif

#ifndef CONIO_H
     #include <conio.h>
#endif

//If you have any of your own header files, then include them the same way
#ifndef USER_AVL_HEADER_FILE
     #include <user_avl_header_file.h>
#endif    

#endif   // INCLUDES_H

然后就像你有你的头文件名“user_avl_header_file.h”,然后在那个头文件中再次放置头文件:

#include "includes.h"

#ifndef USER_AVL_HEADER_FILE
#define USER_AVL_HEADER_FILE

/*your class and your code*/

#endif    //USER_AVL_HEADER_FILE

并且在您的源文件中只包含主头文件“includes.h”而无需担心。

于 2014-08-18T11:09:58.993 回答