Objective-C中#import和#include有什么区别?
Objective-C中#import和#include之间有什么区别,有时候你应该使用另一个呢? 是否被弃用?
我正在阅读以下教程: http ://www.otierney.net/objective-c.html#preamble及其关于#import和#include的段落似乎与自身矛盾或者至less不清楚。
#import指令作为#include的改进版本添加到Objective-C中。 然而,是否有所改善仍然是一个争议问题。 #import确保一个文件只包含一次,所以你永远不会有recursion包含的问题。 但是,大多数体面的头文件无论如何保护自己,所以它不是一个真正的好处。
基本上,由您决定要使用哪一个。 我倾向于#import头文件Objective-C的东西(如类定义等)和#包括我需要的标准C的东西。 例如,我的一个源文件可能如下所示:
#import <Foundation/Foundation.h> #include <asl.h> #include <mach/mach.h>
似乎对预处理器有很多困惑。
当编译器看到一个#include
,它会用所包含的文件的内容replace那一行,而不会问任何问题。
所以如果你有这个内容的文件ah
:
typedef int my_number;
和一个文件bc
与这个内容:
#include "ah" #include "ah"
文件bc
将被编译前的预处理器翻译为
typedef int my_number; typedef int my_number;
这将导致编译器错误,因为my_number
types被定义了两次。 即使定义相同,C语言也不允许这样做。
由于标题经常用于多个地方,因此通常在C中使用警卫 。看起来像这样:
#ifndef _a_h_included_ #define _a_h_included_ typedef int my_number; #endif
文件bc
在进行预处理之后,仍然会将头中的全部内容放入其中。 但是第二个实例会被忽略,因为macros_a_h_included_
已经被定义了。
这工作得很好,但有两个缺点。 首先,必须写入包括卫兵,并且每个头文件中的macros名称必须是不同的。 其次,编译器仍然需要查找头文件,并按照包含的顺序阅读它。
Objective-C具有#import
预处理器指令(它也可用于带有一些编译器和选项的C和C ++代码)。 这和#include
几乎一样,但是它也在内部注意到哪个文件已经被包含了。 第一次遇到时, #import
行只被replace为指定文件的内容。 每一次之后,它都被忽略了。
我同意杰森。
我被抓到了这样做:
#import <sys/time.h> // to use gettimeofday() function #import <time.h> // to use time() function
对于GNU gcc,它一直抱怨time()函数没有被定义。
于是我把#import改成了#include,一切就OK了。
原因:
你#import <sys / time.h>:
<sys / time.h>通过使用#defines只包含<time.h>的一部分
你#import <time.h>:
不行。 即使只有<time.h>的一部分已经被包含,如
就#import而言,该文件现在已经完全包含在内。
底线:
C / C ++头文件传统上包含其他包含文件的一部分。
所以对于C / C ++头文件,使用#include。
对于objc / objc ++头文件,使用#import。
#include
作用就像C #include
。
#import
跟踪哪些头文件已被包含,并且如果在编译单元中多次导入头文件,则会被忽略。 这使得没有必要使用标头警卫。
底线只是在Objective-C中使用#import
,如果您的头文件不止一次导入了某个东西,请不要担心。
我知道这个线程是旧的…但在“现代”..有一个远远优越的“包括战略”通过铛的@import
模块 – 这是经常忽略..
通过用更健壮,更高效的语义模型replace文本预处理器包含模型,模块改进了对软件库API的访问。 从用户的angular度来看,代码只是略有不同,因为它使用的是一个导入声明而不是#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没有影响…因为模块本身被编译为独立的独立模块。 此外,导入模块时,将自动提供使用模块所需的任何链接器标志。 这个语义导入模型解决了预处理器包含模型的许多问题。
要启用模块,请在编译时CLANG_ENABLE_MODULES
Xcode
的命令行标志-fmodules
aka CLANG_ENABLE_MODULES
。 如上所述,这个策略消除了任何和所有的LDFLAGS
。 如在,您可以删除任何“OTHER_LDFLAGS”设置,以及任何“链接”阶段..
我发现编译/启动时间“感觉”更快捷(或者可能只是在“链接”时没有什么滞后),而且还提供了清除现在无关的Project-Prefix.pch文件的好机会,相应的构build设置, GCC_INCREASE_PRECOMPILED_HEADER_SHARING
, GCC_PRECOMPILE_PREFIX_HEADER
和GCC_PREFIX_HEADER
等
此外,虽然没有很好的文档…你可以创buildmodule.map
s为自己的框架,并包括在同一个方便的方式。 你可以看看我的ObjC-Clang-Modules github回购的一些例子,了解如何实现这样的奇迹。
如果你熟悉C ++和macros,那么
#import "Class.h"
类似于
{ #pragma once #include "class.h" }
这意味着你的类只会在应用运行时加载一次。
如果你在.h文件中包含两个文件比编译器会产生错误。 但是如果你多次input一个文件,编译器会忽略它。
在这种情况下,我的一个.h
文件中有一个全局variables导致了这个问题,我通过在它前面添加了extern
来解决这个问题。
#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”放入你的代码中,它里面的内容也不会被重新声明。