Objective-Cの#importと#includeの違いは何ですか?


385

Objective-Cの#importと#includeの違いは何ですか?また、どちらを使用する必要があるのですか?廃止予定ですか?

私は次のチュートリアルを読んでいました:http : //www.otierney.net/objective-c.html#preambleと#importと#includeに関するその段落は、それ自体と矛盾するようです、または少なくとも不明確です。

回答:


340

#importディレクティブは、#includeの改良バージョンとしてObjective-Cに追加されました。しかし、それが改善されるかどうかはまだ議論の問題です。#importにより、ファイルが一度だけインクルードされることが保証されるため、再帰的なインクルードで問題が発生することはありません。ただし、ほとんどのまともなヘッダーファイルはとにかくこれから自分自身を保護するため、実際にはそれほどメリットはありません。

基本的に、どちらを使用するかを決めるのはあなた次第です。(クラス定義などの)Objective-Cのヘッダーを#importし、必要な標準のCのものを#includeする傾向があります。たとえば、ソースファイルの1つは次のようになります。

#import <Foundation/Foundation.h>

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

65
ヘッダーファイルにインクルードガードが含まれている場合でも、#includeを使用すると、コンパイル中にパフォーマンスが低下します。コンパイラーは各ヘッダーファイルを開いてインクルードガードに気づく必要があります。
マットディラード

4
ヘッダーガードは、ヘッダーがソースファイルに1回だけ含まれるようにするプリプロセッサディレクティブです。
Jason Coco、

8
#importは実際にはObjective-CではなくGCCによる追加だと思います。GCC(またはClang)でコンパイルする限り、ObjC以外の言語で使用できます
Dave DeLong

34
@dave-#importは、プリプロセッサへのObjective-Cの追加です。GCCは、CおよびC ++ソースファイルでも同様にサポートしますが、移植可能な従来のヘッダーガードを優先して、CまたはC ++では使用しないことを公式に提案しています。ただし、すべてのObjective-Cプリプロセッサには#importを含める必要があります。
Jason Coco

13
ヘッダーガードは、先頭に追加する場所です:#ifndef myheader #define myheader ...ヘッダーコードが続きます...#endif
Tim

359

プリプロセッサに関しては多くの混乱があるようです。

コンパイラーが#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が2回定義されているため、コンパイラエラーが発生します。定義は同じですが、これはC言語では許可されていません。

ヘッダーは複数の場所で使用されることが多いため、インクルードガードは通常Cで使用されます。これは次のようになります。

 #ifndef _a_h_included_
 #define _a_h_included_

 typedef int my_number;

 #endif

ファイルb.cは、前処理された後も、ヘッダーの内容全体が2回残っています。ただし、マクロ_a_h_included_はすでに定義されているため、2番目のインスタンスは無視されます。

これは非常にうまく機能しますが、2つの欠点があります。最初に、インクルードガードを記述する必要があります。また、マクロ名はヘッダーごとに異なる必要があります。次に、コンパイラーはヘッダーファイルを探して、含まれている回数だけ読み取る必要があります。

Objective-Cには#importプリプロセッサー命令があります(一部のコンパイラーとオプションでCおよびC ++コードに使用することもできます)。これはとほぼ同じですが#include、内部でどのファイルが既にインクルードされているかも記録します。この#import行は、最初に見つかったときに、指定されたファイルの内容によってのみ置き換えられます。その後は毎回無視されます。


5
これは受け入れられたものより良い答えです。@ギル、あなたは受け入れられた答えを変えるべきです。
Nguyen Minh Binh 2013年

6
7000行のテンプレートヘッダーファイルで4 #include秒を#importsに変更すると、コンパイルとXCodeインテリセンスの応答性が大幅に向上します。(私はそれを想像しているとは思いません)
ボボボボ2013

63

私はジェイソンに同意します。

私はこれをしていることに引っ掛かりました:

#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を使用します。


2
clangにはこの未定義の問題がないようです。
おっと2017

23

#includeCと同じように動作し#includeます。

#importどのヘッダーが既に含まれているかを追跡し、コンパイル単位でヘッダーが複数回インポートされた場合は無視されます。これにより、ヘッダーガードを使用する必要がなくなります。

一番下の行は#importObjective-Cで使用するだけであり、ヘッダーが何かを何度もインポートすることになっても心配しないでください。


2
Cの#includeに慣れていないふりをして(主に私が慣れていないため)、#includeと#importの主な違いは何ですか?また、ヘッダーガードとは何か教えてもらえますか?
ライアンギル

@ライアン:スヴェンの答えを見てください。
Adrian Petrescu

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"
}

つまり、アプリの実行時にクラスが1回だけ読み込まれます。


これは#pragmaのサポートされている使用法ですか?プラグマが機能するためには、プラグマがインクルードedファイル内にある必要があるといつも思っていました。
uliwitness 2015

@uliwitnessあなたは正しいです。#pragma onceインクルードを実行するファイルではなく、インクルードファイルに配置されます。そのため-1。
herzbube

1

場合.hによっては、問題の原因となっているファイルの1つにグローバル変数があり、そのextern前に追加することで解決しました。


0

.hファイルにファイルを2回#includeすると、コンパイラーはエラーを出します。しかし、ファイルを複数回インポートすると、コンパイラはそれを無視します。


8
#include同じファイルを2回使用してもエラーになりません
kennytm

1
@KennyTMのコメントを補足するために、通常のヘッダーガード(#ifndef FILE_NAME_H #define FILE_NAME_H #end)がある場合、同じヘッダーで同じファイルを2回#include-ingしてもコンパイルエラーは発生しません。これは予想される慣行です。#importを使用すると、ヘッダーガードは必要ありません。
jbat100

@ jbat100:#includeは単にコピーアンドペーストのメカニズムです。#include"Xマクロ"のように、インクルードガードなしで意図的に複数回使用されています。
kennytm

ファイルを2回含めると、含める内容によってはエラーが発生する可能性があります。#includeある種のテンプレートを実装するために使用されるCコードを見てきました。彼らはを行い、#defineヘッダーを含め、#undefdをやり直し#define、同じヘッダーをもう一度含めました。これにより、defineの値が異なるため、コードがパラメーター化され、有効になり、2回インクルードされました。したがって#include、を使用することには利点がありますが、C ++やObjCなどの最新の言語を使用している場合は、通常これは必要ありません。
uliwitness 2015

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回入れても、その内部は再宣言されません。


0
#include + guard == #import

#include guardWiki-マクロガード、ヘッダーガード、またはファイルガードによりpreprocessor、ビルド時間を遅くする可能性のあるによってヘッダーを二重に含めることができなくなります

次のステップは

.pch[概要] =>@import [概要]

[#import in .hまたは.m]

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.