Objective-C中的#import和#include有什么区别?


384

在Objective-C中,#import和#include之间有什么区别?在某些情况下,您应该一并使用?被弃用了吗?

我正在阅读以下教程:http : //www.otierney.net/objective-c.html#preamble及其有关#import和#include的段落似乎相矛盾,或者至少不清楚。

Answers:


341

#import指令已作为#include的改进版本添加到了Objective-C。但是,是否进行改进仍是一个有争议的问题。#import确保文件只包含一次,因此您不会遇到递归包含的问题。但是,大多数不错的头文件仍然可以防止这种情况的发生,因此,实际上并没有太大的好处。

基本上,由您决定要使用哪个。我倾向于#import Objective-C事物的标题(例如类定义之类),并#include我需要的标准C事物。例如,我的一个源文件可能如下所示:

#import <Foundation/Foundation.h>

#include <asl.h>
#include <mach/mach.h>

63
即使头文件包含include防护,如果您使用#include,在编译过程中仍然会降低性能-编译器必须打开每个头文件以注意include防护。
Matt Dillard

4
标头防护是一个预处理器指令,可确保标头在源文件中仅包含一次。
杰森·可可

8
我认为#import实际上是GCC的添加,而不是Objective-C的添加。只要您使用GCC(或Clang)进行编译,就可以在非ObjC语言中使用它
Dave DeLong 2009年

33
@dave-#import是对Objective-C的补充。GCC也只在C和C ++源文件中支持它,尽管他们正式建议不要在C或C ++中使用它,而是使用可移植的传统标头保护符。但是,所有Objective-C预处理程序都必须包含#import。
杰森·可可

13
标头后卫是您添加到顶部的位置:#ifndef myheader #define myheader ...后跟标头代码...#endif
2012年

358

关于预处理器似乎有很多困惑。

编译器看到一个#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语言也不允许这样做。

由于标头经常在一个以上的地方使用,include防护通常在C中使用。这看起来像这样:

 #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行仅在首次遇到时才被命名文件的内容替换。此后每次都将被忽略。


4
这是比公认的更好的答案。@Guill,您应该更改接受的答案。
Nguyen Minh Binh,2013年

5
在7000行模板头文件上将4更改#include#imports 后,编译和XCode智能感知响应能力得到了显着的性能改进。(我想我没有想象中的)
bobobobo

62

我同意杰森。

我被发现这样做了:

#import <sys/time.h>  // to use gettimeofday() function
#import <time.h>      // to use time() function

对于GNU gcc,它一直抱怨time()函数未定义。

因此,然后我将#import更改为#include,一切正常。

原因:

您#import <sys / time.h>:
    <sys / time.h>通过使用#defines 仅包含<time.h> 的一部分

您#import <time.h>:
    不行。即使仅包含<time.h>的一部分,但
    就#import而言,该文件现在已完全包含在内。

底线:

C / C ++传统上标头包括部件的其他包含文件。
因此,对于C / C ++标头,请使用#include。
对于objc / objc ++标头,请使用#import。


1
似乎c没有这个未定义的问题。
哎呀,

23

#include就像C一样工作#include

#import跟踪哪些头文件已被包含,如果在编译单元中多次导入头文件,则将其忽略。这样就不必使用标题防护。

最重要的一点是#import在Objective-C中使用,不用担心标题是否多次导入了东西。


2
假装一分钟我不熟悉C #include(主要是因为我不熟悉),#include和#import之间的主要区别是什么?另外,你能告诉我什么是头球后卫吗?
Ryan Guill

@Ryan:看看Sven的答案。
阿德里安·彼得雷斯库

13

我知道这个线程很旧...但是在“现代时代” ..通过clang的@import模块有一个非常优越的“包含策略” -通常被忽略。

通过将文本预处理器包含模型替换为更健壮,更有效的语义模型,模块改善了对软件库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_MODULESXcode-在编译时。如上所述,该策略消除了ANY和ALL LDFLAGS。与之类似,您可以删除任何“ OTHER_LDFLAGS”设置以及任何“链接”阶段。

在此处输入图片说明

我发现编译/启动时间可以使您“感觉”更加敏捷(或者“链接”时可能会有更少的延迟?)..而且,它还提供了一个绝佳的机会来清除现在多余的Project-Prefix.pch文件,并且相应的构建设置GCC_INCREASE_PRECOMPILED_HEADER_SHARINGGCC_PRECOMPILE_PREFIX_HEADER以及GCC_PREFIX_HEADER

另外,尽管文档不足,您也可以module.map为自己的框架创建,并以方便的方式将它们包括在内。 您可以查看我的ObjC-Clang-Modules github存储库,以获取有关如何实现此类奇迹的一些示例。


4

如果您熟悉C ++和宏,那么

#import "Class.h" 

类似于

{
#pragma once

#include "class.h"
}

这意味着您的类仅在您的应用运行时才加载一次。


这是#pragma的受支持的用法吗?我一直认为是必要的附注里面的includ 编辑文件的工作。
uliwitness

@uliwitness你是正确的。#pragma once放在包含的文件中,而不是执行包含的文件中。-1。
herzbube

1

在可能的情况下,我的一个.h文件中有一个导致该问题的全局变量,我通过extern在其前面添加来解决了该问题。


0

如果在#.h文件中#include一个文件两次,则编译器将报错。但是,如果您多次导入文件,编译器将忽略该文件。


8
#include同一文件两次不会导致错误。
kennytm

1
为了补充@KennyTM的注释,如果存在通常的标头工具(#ifndef FILE_NAME_H #define FILE_NAME_H #end),则在同一标头中#include-两次在同一标头中不会导致编译错误。这是预期的做法。使用#import不需要标题保护。
jbat100

@ jbat100:#include只是一种复制粘贴机制。故意使用#include多个不包含包括“ X宏”在内的保护措施的情况。
kennytm 2012年

两次包含一个文件可能会导致错误,具体取决于您所包含的内容。我看过用于#include实现一种模板的C代码。他们做了a #define,包括标头,#undefd并重做了#define,再次包含了相同的标头。由于定义的值不同,因此导致代码被参数化,有效并包含两次。因此,使用会有很多好处#include,但是如果您使用的是C ++或ObjC之类的现代语言,则通常不需要。
uliwitness

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在代码中放置n次“ otherfile.h”,也不会在其中声明它。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.