Objective-C中#import和#include之间有什么区别,有时候你应该使用一个而不是另一个吗?一个被弃用了吗?
我正在阅读以下教程:http://www.otierney.net/objective-c.html#preamble及其关于#import和#include的段落似乎自相矛盾,或者至少不清楚。
答案 0 :(得分:343)
预处理器似乎存在很多混淆。
当编译器看到#include
用替换文件的内容替换该行时,编译器会做什么,没有问题。
因此,如果您有一个包含此内容的文件a.h
:
typedef int my_number;
以及包含此内容的文件b.c
:
#include "a.h"
#include "a.h"
文件b.c
将在编译到
typedef int my_number;
typedef int my_number;
将导致编译器错误,因为类型my_number
被定义了两次。即使定义相同,C语言也不允许这样做。
由于标题通常用于多个地方,因此通常在C中使用 include guards 。这看起来像这样:
#ifndef _a_h_included_
#define _a_h_included_
typedef int my_number;
#endif
文件b.c
在预处理后仍然会有两次标题的全部内容。但是第二个实例将被忽略,因为已经定义了宏_a_h_included_
。
这很有效,但有两个缺点。首先必须编写包含警戒,并且每个标题中的宏名称必须不同。其次,编译器仍然需要查找头文件并按原样读取它。
Objective-C具有#import
预处理器指令(它也可以用于带有一些编译器和选项的C和C ++代码)。这与#include
几乎相同,但它也会在内部记录哪些文件已被包含在内。 #import
行仅在遇到第一次时被命名文件的内容替换。之后每次都被忽略了。
答案 1 :(得分:335)
#import指令已添加到Objective-C,作为#include的改进版本。然而,它是否得到改善仍然是一个争论的问题。 #import确保文件只被包含一次,这样你就不会遇到递归包含问题。然而,大多数体面的头文件无论如何都能保护自己免受此类攻击,所以它并没有那么大的好处。
基本上,由您决定要使用哪个。我倾向于#import标头用于Objective-C事物(比如类定义等)和#include标准C我需要的东西。例如,我的一个源文件可能如下所示:
#import <Foundation/Foundation.h>
#include <asl.h>
#include <mach/mach.h>
答案 2 :(得分:61)
我同意杰森。
我抓住了这个:
#import <sys/time.h> // to use gettimeofday() function
#import <time.h> // to use time() function
对于GNU gcc,它一直抱怨time()函数是 没有定义。
然后我将#import改为#include,一切顺利。
原因:
你#import&lt; sys / time.h&gt;:
&LT; SYS / time.h中&GT;仅包含&lt; time.h&gt;的部分使用#defines
你#import&lt; time.h&gt;:
不行。即使只是&lt; time.h&gt;的一部分。已被列入,作为
就#import而言,该文件现已包含完全。
底线:
C / C ++标题传统上包括其他包含文件的部分
因此,对于C / C ++标头,请使用#include。
对于objc / objc ++标头,请使用#import。
答案 3 :(得分:22)
#include
就像C #include
一样。
#import
会跟踪已包含哪些标头,如果在编译单元中多次导入标头,则会忽略该标头。这使得不必使用标题保护。
底线只是在Objective-C中使用#import
,如果您的标题不止一次导入某些内容,请不要担心。
答案 4 :(得分:13)
我知道这个帖子已经老了......但在“现代”中......通过clang's @import
modules有一个更优越的“包含策略” - 这是经常被忽视的......
模块通过将文本预处理器包含模型替换为更健壮,更高效的语义模型,改进了对软件库API的访问。从用户的角度来看,代码看起来只是略有不同,因为一个使用导入声明而不是#include预处理器指令:
@import Darwin; // Like including all of /usr/include. @see /usr/include/module.map
或
@import Foundation; // Like #import <Foundation/Foundation.h>
@import ObjectiveC; // Like #import <objc/runtime.h>
但是,此模块导入的行为与相应的#include完全不同:当编译器看到上面的模块导入时,它会加载模块的二进制表示,并使其API直接可供应用程序使用。导入声明之前的预处理程序定义对提供的API没有影响...因为模块本身被编译为单独的独立模块。此外,导入模块时,将提供使用该模块所需的任何链接器标志自动。这种语义导入模型解决了预处理器包含模型的许多问题。
要启用模块,请在编译时在-fmodules
中传递命令行标志CLANG_ENABLE_MODULES
又名Xcode
。如上所述..这种策略避免了任何和所有LDFLAGS
。在,您可以删除任何“OTHER_LDFLAGS”设置,以及任何“链接”阶段..
我发现编译/启动时间“感觉”更加快速(或者可能,“链接”时只有较少的延迟?)..而且,提供了清除现在无关的Project-Prefix.pch的绝佳机会文件和相应的构建设置,GCC_INCREASE_PRECOMPILED_HEADER_SHARING
,GCC_PRECOMPILE_PREFIX_HEADER
和GCC_PREFIX_HEADER
等。
此外,虽然没有详细记录......您可以为自己的框架创建module.map
并以相同的方式包含它们。 You can take a look at my ObjC-Clang-Modules github repo for some examples of how to implement such miracles.
答案 5 :(得分:4)
如果您熟悉C ++和宏,那么
#import "Class.h"
类似于
{
#pragma once
#include "class.h"
}
这意味着只有在您的应用运行时,您的类才会加载一次。
答案 6 :(得分:1)
如果你在.h文件中#include一个文件两次而不是编译器会给出错误。 但是如果你#cmport一个文件不止一次,编译器就会忽略它。
答案 7 :(得分:1)
在可能的情况下,我的.h
个文件中有一个导致问题的全局变量,我通过在其前面添加extern
解决了这个问题。
答案 8 :(得分:0)
#include
它过去常常从另一个文件中获取“事物”到使用#include
的文件。
例如:
:main.cpp
#include "otherfile.h"
// some stuff here using otherfile.h objects,
// functions or classes declared inside
在每个头文件(* .h)的顶部使用标头防护,以防止包含同一个文件多一次(如果它发生,您将收到编译错误)。
文件中的:otherfile.h
#ifndef OTHERFILE
#define OTHERFILE
// declare functions, classes or objects here
#endif
即使您在代码中放入#include
“otherfile.h”n,也不会重新声明其中的内容。
答案 9 :(得分:0)