Objective-C'de #import ve #include arasındaki fark nedir?


385

Objective-C'de #import ve #include arasındaki farklar nelerdir ve birini diğerinin üzerinde kullanmanız gereken zamanlar var mı? Biri kullanımdan kaldırıldı mı?

Aşağıdaki öğreticiyi okuyordum: http://www.otierney.net/objective-c.html#preamble ve #import ve #include ile ilgili paragrafı kendisiyle çelişiyor gibi görünüyor ya da en azından belirsiz.

Yanıtlar:


340

#İmport yönergesi, #include'un geliştirilmiş bir sürümü olarak Objective-C'ye eklenmiştir. Bununla birlikte, iyileştirilip iyileştirilmediği hala tartışma konusudur. #import, bir dosyanın yalnızca bir kez eklenmesini sağlar, böylece özyinelemeli içeriklerle ilgili bir sorun yaşamazsınız. Ancak, çoğu iyi başlık dosyası kendilerini buna karşı korur, bu yüzden gerçekten çok fazla bir faydası yoktur.

Temel olarak, hangisini kullanmak istediğinize karar vermek size kalmış. Objective-C şeyler (# sınıf tanımları ve benzeri) için #import başlıkları ve # ihtiyacım olan standart C şeyler dahil eğilimindedir. Örneğin, kaynak dosyalarımdan biri şöyle görünebilir:

#import <Foundation/Foundation.h>

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

64
Başlık dosyalarında korumalar olsa bile, #include kullanırsanız derleme sırasında yine de bir performans isabet vardır - derleyici, ekleme korumalarını fark etmek için her başlık dosyasını açmalıdır.
Matt Dillard

4
başlık koruması, bir başlığın kaynak dosyaya yalnızca bir kez eklenmesini sağlayan bir önişlemci direktifidir.
Jason Coco

8
#İmport'un aslında Objective-C tarafından değil, GCC'nin bir eki olduğunu düşünüyorum. GCC (veya Clang) ile derlediğiniz sürece ObjC dışı dillerde kullanabilirsiniz
Dave DeLong

34
@dave - #import önişlemciye Objective-C ekidir. GCC sadece C ve C ++ kaynak dosyalarında da destekliyor, ancak resmi olarak taşınabilir veya geleneksel başlık korumaları lehine C veya C ++ 'da kullanılmamasını öneriyorlar. Ancak tüm Objective-C ön işlemcileri #import içermelidir.
Jason Coco

13
Başlık muhafızı en üste eklediğiniz yerdir: #ifndef myheader #define myheader ... ardından başlık kodu ...#endif
Tim

359

Önişlemci ile ilgili çok fazla karışıklık var gibi görünüyor.

Derleyicinin, #includebu satırı içerdiği dosyaların içeriği ile değiştirdiğini gördüğü zaman ne yapar ?

a.hBu içeriğe sahip bir dosyanız varsa :

typedef int my_number;

ve b.cbu içeriğe sahip bir dosya :

#include "a.h"
#include "a.h"

dosya b.cderlenmeden önce önişlemci tarafından çevrilecektir.

typedef int my_number;
typedef int my_number;

tür my_numberiki kez tanımlandığından derleyici hatasına neden olur . Tanım aynı olmasına rağmen, C dili tarafından buna izin verilmez.

Bir başlık genellikle birden fazla yerde kullanıldığından, genellikle C'de kullanılan korumaları içerir . Bu şöyle görünür:

 #ifndef _a_h_included_
 #define _a_h_included_

 typedef int my_number;

 #endif

Dosya b.c, önceden işlendikten sonra üstbilginin tüm içeriğini iki kez içerecektir. Ancak, makro _a_h_included_zaten tanımlanmış olacağından, ikinci örnek yok sayılır .

Bu gerçekten iyi çalışıyor, ancak iki dezavantajı var. Her şeyden önce içerme korumaları yazılmalı ve makro adı her başlıkta farklı olmalıdır. İkincisi, derleyici hala başlık dosyasını aramalı ve içerdiği sıklıkta okumalıdır.

Objective-C #importönişlemci komutuna sahiptir (bazı derleyiciler ve seçeneklerle C ve C ++ kodu için de kullanılabilir). Bu neredeyse aynıdır #include, ancak dahili olarak hangi dosyanın zaten dahil edildiğini de not eder. #importHat sadece karşılaşıldığında ilk defa adlı dosyanın içeriği ile yer değiştirir. Bundan sonra her seferinde göz ardı edilir.


5
Bu, kabul edilenden daha iyi bir cevaptır. @Gill, kabul edilen cevabı değiştirmelisin.
Nguyen Minh Binh

6
7000 satır şablon başlık dosyasında 4 #includesaniyeyi s olarak değiştirdikten sonra #import, derleme ve XCode intellisense yanıt hızında gözle görülür bir performans artışı var. (Hayal ettiğimi sanmıyorum)
bobobobo

63

Jason'a katılıyorum.

Bunu yaparken yakalandım:

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

GNU gcc için time () fonksiyonunun tanımlanmadığından şikayet etmeye devam etti.

Sonra #import'u #include olarak değiştirdim ve her şey yolunda gitti.

Sebep:

#İmport <sys / time.h>:
    <sys / time.h>, #defines kullanarak <time.h> öğesinin yalnızca bir bölümünü içerir

Siz #import <time.h>:
    Gitme.
    #İmport söz konusu olduğunda, <time.h> öğesinin yalnızca bir kısmı zaten dahil edilmiş olsa da , bu dosya zaten tamamen dahil edilmiştir.

Sonuç olarak:

C / C ++ başlıkları geleneksel olarak diğer içerme dosyalarının bölümlerini içerir.
C / C ++ üstbilgileri için #include kullanın.
Objc / objc ++ başlıkları için #import kullanın.


2
Görünüşe göre clang'da bu tanımlanmamış bir sorun yok.
ooops

23

#includetıpkı C gibi çalışır #include.

#importhangi başlıkların önceden dahil edildiğini izler ve bir başlık bir derleme birimine birden fazla içe aktarılırsa yoksayılır. Bu, başlık korumalarının kullanılmasını gereksiz kılar.

Alt satırda sadece #importObjective-C kullanmak ve başlıkları bir kereden fazla bir şey ithal rüzgar endişe etmeyin.


2
bir dakikalığına C #include'a aşina olmadığımı iddia ederek (çoğunlukla ben olmadığım için), #include ve #import arasındaki temel fark nedir? Ayrıca, başlık muhafızının ne olduğunu söyleyebilir misiniz?
Ryan Guill

@Ryan: Sven'in cevabına bakın.
Adrian Petrescu

13

Bu iş parçasının eski olduğunu biliyorum ... ama "modern zamanlarda" .. clang @importmodülleri üzerinden çok üstün bir "dahil strateji" vardır - bu çoğu zaman gözden kaçan ..

Modüller, metin önişlemci içerme modelini daha sağlam, daha verimli bir anlamsal modelle değiştirerek yazılım kitaplıkları API'sine erişimi geliştirir. Kullanıcının bakış açısından, kod sadece biraz farklı görünüyor, çünkü biri #include önişlemci yönergesi yerine bir içe aktarma bildirimi kullanıyor:

@import Darwin; // Like including all of /usr/include. @see /usr/include/module.map

veya

@import Foundation;  //  Like #import <Foundation/Foundation.h>
@import ObjectiveC;  //  Like #import <objc/runtime.h>

Ancak, bu modül içe aktarma, karşılık gelen #include'dan oldukça farklı davranır: derleyici modül içe aktarma işlemini gördüğünde, modülün ikili sunumunu yükler ve API'sini doğrudan uygulamaya sunar. İçe aktarma bildiriminden önceki önişlemci tanımlarının sağlanan API üzerinde hiçbir etkisi yoktur ... çünkü modülün kendisi ayrı, bağımsız bir modül olarak derlenmiştir. Ayrıca, modülü içe aktarırken modülü kullanmak için gereken bağlayıcı bayrakları otomatik olarak sağlanacaktır. Bu semantik içe aktarma modeli, önişlemci dahil etme modelinin birçok sorununu ele alır.

, Modülleri etkinleştirmek komut satırı işareti geçmek için -fmodulesaka CLANG_ENABLE_MODULESiçinde Xcode- derleme zamanında. Yukarıda belirtildiği gibi .. bu strateji HERHANGİ BİRİ ve TÜMÜNÜ ortadan kaldırır LDFLAGS. Olduğu gibi, "OTHER_LDFLAGS" ayarlarının yanı sıra "Bağlama" aşamalarını KALDIRABİLİRSİNİZ.

resim açıklamasını buraya girin

Ben çok daha snappier "hissetmek" için derleme / başlatma süreleri bulmak (ya da, muhtemelen "bağlarken" daha az bir gecikme var?) .. ve ayrıca, şimdi yabancı Project-Prefix.pch dosyasını temizlemek için büyük bir fırsat sağlar ve inşa ayarlarını karşılık gelen GCC_INCREASE_PRECOMPILED_HEADER_SHARING, GCC_PRECOMPILE_PREFIX_HEADERve GCC_PREFIX_HEADERvb

Ayrıca, iyi belgelenmemiş olsa da… module.mapKendi çerçeveleriniz için s oluşturabilir ve bunları aynı uygun şekilde ekleyebilirsiniz . Bu tür mucizelerin nasıl uygulanacağına dair bazı örnekler için ObjC-Clang-Modules github repo'ma bir göz atabilirsiniz.


4

C ++ ve makrolara aşina iseniz,

#import "Class.h" 

benzer

{
#pragma once

#include "class.h"
}

Bu, Sınıfınızın uygulamanız çalıştığında yalnızca bir kez yükleneceği anlamına gelir.


Bu #pragma'nın desteklenen bir kullanımı mı? Her zaman pragmanın çalışmak için dahil ed dosyasının içinde olması gerektiğini düşündüm .
uliwitness

@uliwitness Doğru. #pragma onceiçerme dosyasına yerleştirilir, içerme işlemini gerçekleştiren dosyaya yerleştirilmez. Bunun için -1.
herzbube

1

Belki de dosyamın birinde .hsoruna neden olan global bir değişkenim vardı ve externönüne ekleyerek çözdüm .


0

# .H dosyalarına bir dosyayı derleyiciden iki kez eklerseniz hata verir. Ancak bir dosyayı birden fazla içe aktarırsanız derleyici dosyayı yok sayar.


8
#includeaynı dosya iki kez hataya neden olmaz .
kennytm

1
@ KennyTM'in yorumunu tamamlamak için, # aynı dosyanın iki kez aynı başlığa eklenmesi , normal başlık gardiyanları (#ifndef FILE_NAME_H #define FILE_NAME_H #end) varsa derleme hatasıyla sonuçlanmaz . Bu beklenen bir uygulamadır. #İmport kullanıldığında başlık korumalarına gerek yoktur.
jbat100

@ jbat100: #includebasitçe bir kopyala ve yapıştır mekanizmasıdır. Kapatma #includekorumaları olmadan, örneğin "X makrosu" olmadan , birden fazla kez kasıtlı kullanım vardır .
kennytm

Bir dosyayı iki kez eklemek, neleri eklediğinize bağlı olarak hatalara neden olabilir . #includeBir çeşit şablon uygulamak için kullanılan C kodu gördüm . Bir mi #define, bir başlık dahil #undefd ve redid #define, aynı başlığını bir kez dahil. Bu, kodun parametreleştirilmesi, geçerli olması ve tanımlamanın değeri farklı olduğu için iki kez dahil edilmesiyle sonuçlanmıştır. Bu yüzden kullanmanın avantajları var #include, ancak C ++ veya ObjC gibi modern bir dil kullanıyorsanız, genellikle buna ihtiyacınız yoktur.
uliwitness

0

#includebaşka bir dosyadan #includekullanılan dosyaya "şeyler" alırdı. Örn:

dosyada: main.cpp

#include "otherfile.h"

// some stuff here using otherfile.h objects,
// functions or classes declared inside

Üstbilgi koruması, aynı dosyanın bir kereden fazla eklenmesini önlemek için her bir üstbilgi dosyasının (* .h) üstünde kullanılır (eğer olursa derleme hataları alırsınız).

dosyada: otherfile.h

#ifndef OTHERFILE
#define OTHERFILE

// declare functions, classes or objects here

#endif

#includekodunuza "otherfile.h" n zamanını koymuş olsanız bile , içerisindeki bu yeniden bildirilmez.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.