【问题标题】:What is the difference between #import and #include in Objective-C?Objective-C 中的#import 和#include 有什么区别?
【发布时间】:2010-10-01 04:18:04
【问题描述】:

Objective-C 中的#import 和#include 之间有什么区别?在某些情况下您应该使用其中一个而不是另一个?是否已弃用?

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

【问题讨论】:

    标签: objective-c import include


    【解决方案1】:

    #include 与 #import

    历史:

    #include => #import => Precompiled Headers .pch => @import Module(ObjC); => import Module(Swift)
    

    [Precompiled Headers .pch]
    [@import Module(ObjC);]
    [import Module(Swift)]

    #include + guard == #import
    

    #include guardWiki - 宏保护、标头保护或文件保护可防止通过 preprocessor 双重包含标头,这会减慢构建时间

    #import 劣势

    适用于文件范围,这就是我们构建时间缓慢的原因,因为编译器必须解析和编译与项目范围中导入的 .h 文件一样多的次数

    [#import in .h or .m]

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        #import 指令作为#include 的改进版本添加到Objective-C。然而,它是否得到改进仍然是一个争论的问题。 #import 确保文件只包含一次,这样您就不会遇到递归包含的问题。但是,无论如何,大多数体面的头文件都会保护自己免受这种情况的影响,因此它并没有太大的好处。

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

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

        【讨论】:

        • 即使头文件包含包含保护,如果您使用#include,编译期间仍然会影响性能——编译器必须打开每个头文件才能注意到包含保护。
        • 我认为#import 实际上是 GCC 的补充,而不是 Objective-C 的补充。只要你用 GCC(或 Clang)编译,你就可以在非 ObjC 语言中使用它
        • @dave - #import 是 Objective-C 对预处理器的补充。 GCC 也仅在 C 和 C++ 源文件中支持它,尽管他们正式建议不要在 C 或 C++ 中使用它,而是支持可移植的传统标头保护。但是,所有 Objective-C 预处理器都必须包含#import。
        • 标题保护是您添加到顶部的位置:#ifndef myheader #define myheader ... 后跟标题代码... #endif
        • 这不是标准与非标准;这是语言与语言,一个意图与另一个意图。如果您使用的是Objective-C 并且您打算包含一个Objective-C 标头,请使用#import。如果您使用 C、C++ 正在使用 Objective-C 并且只想将一个文件内联到另一个文件中,请使用 #include。
        【解决方案4】:

        我知道这个帖子很老了......但在“现代”......通过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 没有影响……因为模块本身被编译为单独的独立模块。此外,在导入模块时,将自动提供使用该模块所需的任何链接器标志。这种语义导入模型解决了预处理器包含模型的许多问题。

        要启用模块,请在编译时在 Xcode- 中传递命令行标志 -fmodules aka CLANG_ENABLE_MODULES。如上所述.. 这种策略避免了任何和所有LDFLAGS。如在,您可以删除任何“OTHER_LDFLAGS”设置,以及任何“链接”阶段..

        我发现编译/启动时间“感觉”快得多(或者可能,“链接”时延迟更少?)..而且,提供了清除现在无关的 Project-Prefix.pch 的绝佳机会文件,以及相应的构建设置,GCC_INCREASE_PRECOMPILED_HEADER_SHARINGGCC_PRECOMPILE_PREFIX_HEADERGCC_PREFIX_HEADER 等。

        此外,虽然没有很好的记录……您可以为自己的框架创建module.maps,并以同样方便的方式包含它们。 You can take a look at my ObjC-Clang-Modules github repo for some examples of how to implement such miracles.

        【讨论】:

          【解决方案5】:

          我同意杰森的观点。

          我被抓到这样做了:

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

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

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

          原因:

          你#import :
          使用#defines

          仅包含 部分

          你#import :
          不去。尽管只有 的一部分已经包含在内,但
          就 #import 而言,该文件现在已完全包含在内。

          底线:

          C/C++ 标头通常包含其他包含文件的部分
          因此,对于 C/C++ 头文件,请使用 #include。
          对于 objc/objc++ 头文件,使用#import。

          【讨论】:

          • 看来clang没有这个未定义的问题。
          • 这是一个很好的例子,说明了为什么以非侵入性的方式将现代功能 (#import) 引入现有系统具有挑战性。是否应该更新系统库以更好地处理#import ...可能不会。如果是这样,这将以牺牲许多有意或无意地依赖现有行为的现有项目为代价。语言开发是否应该停止引入新的、有用的、前瞻性的功能……不。因此,它从来没有像接受答案中的一些 cmets 所暗示的那样简单。
          • 这是一个糟糕的写入包含文件的明显问题。 gcc 承认了这一点,并重新构建了他们的头文件。头文件不应该依赖于任何包含顺序。
          【解决方案6】:

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

          #import "Class.h" 
          

          类似于

          {
          #pragma once
          
          #include "class.h"
          }
          

          这意味着当你的应用运行时你的类只会被加载一次。

          【讨论】:

          • 这是一次受支持的#pragma 用法吗?我一直认为编译指示需要包含的ed文件中才能工作。
          • @uliwitness 你是对的。 #pragma once 放置在包含文件中,而不是执行包含的文件中。 -1 。
          【解决方案7】:

          #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 次放在你的代码里,它里面的这个也不会被重新声明。

          【讨论】:

            【解决方案8】:

            似乎有很多关于预处理器的混淆。

            编译器在看到#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 中使用。看起来像这样:

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

            【讨论】:

            • 这是比接受的更好的答案。 @Guill,您应该更改接受的答案。
            • 在 7000 行模板头文件上将 4 #includes 更改为 #imports 后,在编译和 XCode 智能感知响应方面有明显的性能提升。 (我不认为我在想象)
            【解决方案9】:

            如果你在 .h 文件中 #include 一个文件两次,编译器就会报错。 但是如果你多次#import 一个文件,编译器会忽略它。

            【讨论】:

            • #include同一个文件两次不会导致错误。
            • 为了补充@KennyTM 的评论,#include-ing 同一个文件在同一个标​​题中两次不会导致编译错误如果通常的标题gards (#ifndef FILE_NAME_H #定义 FILE_NAME_H #end) 在那里。这是预期的做法。不需要使用 #import 标头保护。
            • @jbat100: #include 只是一种复制粘贴机制。多次故意使用 #include 而不包含保护,例如“X 宏”。
            • 两次包含文件可能会导致错误,具体取决于您包含的内容。我见过使用#include 实现一种模板的C 代码。他们做了一个#define,包含了一个标题#undefd,并重做了#define,第二次包含了相同的标题。这导致代码被参数化、有效并包含两次,因为定义的值不同。所以使用#include 是有好处的,但是如果你使用像 C++ 或 ObjC 这样的现代语言,你通常不需要这个。
            【解决方案10】:

            #include 与 C 中的 #include 一样工作。

            #import 跟踪已包含哪些标头,如果在编译单元中多次导入标头,则将其忽略。这使得没有必要使用标题保护。

            最重要的是在 Objective-C 中使用 #import,如果您的标头多次导入某些内容,请不要担心。

            【讨论】:

            • 假装我不熟悉C#include(主要是因为我不熟悉),#include和#import之间的主要区别是什么?另外,你能告诉我什么是头卫吗?
            • @Ryan:看斯文的回答。
            猜你喜欢
            • 2012-04-21
            • 2017-01-09
            • 2011-07-15
            • 2010-09-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-01-29
            • 2010-09-06
            相关资源
            最近更新 更多