Objective-Cの#importと#includeの違いは何ですか?また、一方を他方の上で使用する必要がある場合がありますか?廃止されたものはありますか?
私は次のチュートリアルを読んでいました: http://www.otierney.net/objective-c.html#preamble と#importと#に関する段落includeはそれ自体と矛盾するか、少なくとも不明確です。
#includeの改良バージョンとして#importディレクティブがObjective-Cに追加されました。ただし、改善されているかどうかはまだ議論の余地があります。 #importは、ファイルが一度しかインクルードされないようにし、再帰インクルードで問題が発生しないようにします。ただし、ほとんどの適切なヘッダーファイルはいずれにせよ、これに対して自分自身を保護するため、実際にはそれほど多くの利点はありません。
基本的に、どちらを使用するかを決めるのはあなた次第です。私は、Objective-Cのもの(クラス定義など)の#importヘッダーと、必要な標準Cのものを#includeする傾向があります。たとえば、ソースファイルの1つは次のようになります。
#import <Foundation/Foundation.h>
#include <asl.h>
#include <mach/mach.h>
プリプロセッサに関して多くの混乱があるようです。
コンパイラが#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言語では許可されていません。
多くの場合、ヘッダーは複数の場所で使用されるためincludeガードは通常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
行は、初めて見つかった名前付きファイルの内容によってのみ置き換えられます。それ以降は毎回無視されます。
私はジェイソンに同意します。
私はこれをやっているのを見つけました:
#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>のpartのみが含まれます
#import <time.h>:
立ち入り禁止。 <time.h>の一部のみが既に含まれていたとしても、
#importに関する限り、そのファイルはすでに完全含まれています。
結論:
C/C++ヘッダーには、従来、他のインクルードファイルのpartsが含まれています。
C/C++ヘッダーには#includeを使用します。
objc/objc ++ヘッダーの場合、#importを使用します。
#include
は、Cの#include
と同じように機能します。
#import
は、どのヘッダーが既に含まれているかを追跡し、ヘッダーがコンパイル単位で複数回インポートされた場合は無視されます。これにより、ヘッダーガードを使用する必要がなくなります。
一番下の行は、Objective-Cで#import
を使用するだけであり、ヘッダーが何かを複数回インポートしても問題ありません。
私はこのスレッドが古いことを知っています...しかし、「現代」では. 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に影響を与えません...モジュール自体が独立したスタンドアロンモジュールとしてコンパイルされたためです。さらに、モジュールを使用するために必要なリンカーフラグは、モジュールのインポート時に自動的に提供されます。このセマンティックインポートモデルは、プリプロセッサ包含モデルの多くの問題に対処します。
モジュールを有効にするには、コンパイル時にXcode
-でコマンドラインフラグ-fmodules
aka CLANG_ENABLE_MODULES
を渡します。上記のように..この戦略は、ANYおよびALL LDFLAGS
を不要にします。同様に、「OTHER_LDFLAGS」設定と「リンク」フェーズを削除できます。
私はコンパイル/起動時間をより迅速に「感じる」ことがわかります(または、おそらく「リンク」している間に遅れが少ないのですか?)..また、今は無関係なProject-Prefix.pchファイルをパージする絶好の機会を提供し、対応するビルド設定、GCC_INCREASE_PRECOMPILED_HEADER_SHARING
、GCC_PRECOMPILE_PREFIX_HEADER
、GCC_PREFIX_HEADER
など。
また、十分にドキュメント化されていませんが、独自のフレームワーク用にmodule.map
sを作成し、同じ便利な方法でそれらを含めることができます。 このような奇跡を実装する方法の例については、私のObjC-Clang-Modules githubリポジトリをご覧ください。
C++とマクロに精通している場合は、
#import "Class.h"
と類似しています
{
#pragma once
#include "class.h"
}
これは、アプリの実行時にクラスが一度だけロードされることを意味します。
#import
で使用されるObjective-C
ディレクティブは、C
プログラミング言語から継承した従来の#include
メカニズムとほとんど同じです。唯一の違いは、同じファイルが複数回含まれないようにすることです。これは、C
のヘッダーガードを含めるという一般的なpreprocessor
手法を回避するための小さな利便性です。
preprocessor
(プリプロセッサは、ヘッダーファイル、マクロ展開、条件付きコンパイル、行制御を含める機能を提供します。)各ソースファイル内の各ヘッダーファイルの解析は、プロジェクトが大きくなるとすぐに遅くなり、非効率になります。ソースファイルには同じヘッダーファイルが含まれます。
#import
は、どのヘッダーが既に含まれているかを追跡し、ヘッダーがコンパイル単位で複数回インポートされた場合は無視されます。これにより、ヘッダーガードを使用する必要がなくなります。
#import
を使用する場合、ヘッダーインクルードガードは不要です。それ以外の場合は、#include
と同じです。
#include
を使用すると、同じファイルを何度も含めることができます。
Objective-Cでのファイルのコンパイルは、2つのパスで実行されます。最初に、プリプロセッサがファイルを実行します。プリプロセッサからの出力は、実際のコンパイラに送られます。
#hファイルにファイルを2回インクルードすると、コンパイラーはエラーを出します。ただし、ファイルを複数回インポートすると、コンパイラはそれを無視します。
場合によっては、問題を引き起こしている.h
ファイルの1つにグローバル変数があり、その前に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"をn回挿入したとしても、その中のこれは再宣言されません。