代码之家  ›  专栏  ›  技术社区  ›  Ryan Guill

导入和包含在目标C中有什么区别?

  •  367
  • Ryan Guill  · 技术社区  · 16 年前

    导入和包含在目标C中有什么区别?在某些时候,您应该使用一个而不是另一个?是否已弃用?

    我正在阅读以下教程: http://www.otierney.net/objective-c.html#preamble 它关于“进口”和“包括”的一段似乎自相矛盾,或者至少不清楚。

    9 回复  |  直到 8 年前
        1
  •  331
  •   Reto Koradi    10 年前

    导入指令作为include的改进版本添加到了objective-c中。然而,它是否得到改善仍然是一个争论的问题。#导入确保文件只包含一次,这样就不会出现递归包含问题。然而,大多数合适的头文件无论如何都会保护自己不受此影响,所以这并不是什么真正的好处。

    基本上,由你决定你想用哪一种。我倾向于为Objective-C事物(如类定义等)导入标题,并且包括我需要的标准C事物。例如,我的一个源文件可能如下所示:

    #import <Foundation/Foundation.h>
    
    #include <asl.h>
    #include <mach/mach.h>
    
        2
  •  340
  •   Sven    14 年前

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

    当编译器看到 #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_ 已经定义了。

    这真的很有效,但有两个缺点。首先,必须编写include保护,并且每个头中的宏名称必须不同。其次,编译器仍然需要查找头文件,并尽可能频繁地读取它。

    目标C具有 #import 预处理器指令(它也可以用于C和C++代码,有一些编译器和选项)。这和 包括: 但它也会在内部记录哪些文件已经包含在内。这个 输入输出 只有在第一次遇到指定文件时,行才会被其内容替换。之后每次都会被忽略。

        3
  •  61
  •   bdesham    11 年前

    我同意杰森的观点。

    我被抓到做这件事:

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

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

    然后我把import改为include,一切都正常了。

    原因:

    您导入<sys/time.h>:
    <sys/time.h>仅包括 部分 通过使用定义

    您导入<time.h>:
    不去。即使只包含了<time.h>的一部分,作为
    就导入而言,该文件现在已经 完全地 包括。

    底线:

    传统的C/C++标题包括 部分 其他包括文件。
    因此,对于C/C++头,使用γ包含。
    对于objc/objc++头,使用import。

        4
  •  22
  •   Ferruccio    16 年前

    #include 像C一样工作 包括: .

    #import 跟踪已包含哪些头,如果在编译单元中多次导入头,则忽略这些头。这使得不需要使用收割台防护装置。

    底线就是用 输入输出 在objective-c中,不要担心头部是否会多次导入某些内容。

        5
  •  11
  •   Alex Gray    10 年前

    我知道这条线很旧…但在“现代”中……通过 clang's @import modules -这经常被忽视。

    模块通过将文本预处理器包含模型替换为更健壮、更高效的语义模型来改进对软件库API的访问。从用户的角度来看,代码看起来只是略有不同,因为使用的是导入声明而不是包含预处理器指令:

    @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 . 如中所述,您可以删除任何“其他”设置以及任何“链接”阶段。

    enter image description here

    我发现编译/发布时间“感觉”更快(或者可能,在“链接”时有更少的延迟?)…此外,还提供了清除现在无关的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.

        6
  •  4
  •   LittleBobbyTables - Au Revoir    12 年前

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

    #import "Class.h" 
    

    类似于

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

    这意味着你的类在你的应用程序运行时只加载一次。

        7
  •  1
  •   Husmukh    14 年前

    如果在.h文件中包含两次文件,编译器将给出错误。 但如果您多次导入一个文件,编译器将忽略它。

        8
  •  1
  •   neowinston    9 年前

    在5月份的案例中,我在 .h 导致问题的文件,我通过添加 extern 在它前面。

        9
  •  0
  •   LPL user462990    13 年前

    #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
    

    即使你把 包括: “otherfile.h”n在您的代码中,不会重新声明其中的内容。