Objective-C에서 #import와 #include의 차이점은 무엇입니까?


답변:


341

#import 지시문이 Objective-C에 개선 된 버전의 #include로 추가되었습니다. 그러나 개선 여부는 여전히 논란의 여지가 있습니다. #import를 사용하면 파일이 한 번만 포함되므로 재귀 포함에 문제가 발생하지 않습니다. 그러나 대부분의 괜찮은 헤더 파일은 어쨌든 이것으로부터 자신을 보호하므로 실제로 큰 이점은 아닙니다.

기본적으로 어떤 것을 사용할 것인지 결정하는 것은 귀하의 몫입니다. 나는 # Objective-C 사물 (클래스 정의 등)에 대한 헤더를 가져오고 필요한 표준 C 요소를 포함시키는 경향이 있습니다. 예를 들어, 소스 파일 중 하나가 다음과 같습니다.

#import <Foundation/Foundation.h>

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

63
헤더 파일에 포함 가드가 포함되어 있어도 #include를 사용하면 컴파일 중에 여전히 성능 저하가 발생합니다. 컴파일러는 포함 헤더를 확인하기 위해 각 헤더 파일을 열어야합니다.
Matt Dillard

4
헤더 가드는 헤더가 소스 파일에 한 번만 포함되도록하는 전 처리기 지시문입니다.
Jason Coco

8
#import는 실제로 Objective-C가 아니라 GCC의 추가 사항이라고 생각합니다. 당신은 당신이 GCC (또는 연타) 컴파일 한 비 ObjC 언어로 사용할 수 있습니다
데이브 드롱

33
@dave-#import는 전처리기에 Objective-C를 추가 한 것입니다. GCC는 C 및 C ++ 소스 파일에서도 지원하지만, C, C ++에서는 포터블의 전통적인 헤더 가드를 선호하지 않는 것이 좋습니다. 그러나 모든 Objective-C 전처리 기는 #import를 포함해야합니다.
Jason Coco

13
헤더 가드가 상단에 추가되는 위치 : #ifndef myheader #define myheader ... 뒤에 헤더 코드 ...#endif
Tim

358

전처리 기와 관련하여 많은 혼란이있는 것 같습니다.

컴파일러가 #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_가 이미 정의되었으므로 두 번째 인스턴스는 무시 됩니다.

이것은 실제로 잘 작동하지만 두 가지 단점이 있습니다. 먼저 모든 포함 가드를 작성해야하며 매크로 이름은 모든 헤더에서 달라야합니다. 두 번째로 컴파일러는 여전히 헤더 파일을 찾아서 포함 된대로 자주 읽어야합니다.

Objective-C에는 #import전 처리기 명령어가 있습니다 (일부 컴파일러 및 옵션과 함께 C 및 C ++ 코드에도 사용할 수 있음). 이것은와 거의 동일 #include하지만 내부에 어떤 파일이 이미 포함되어 있는지 기록합니다. #import라인은 단지 그것을 발생 처음으로 지정된 파일의 내용으로 대체됩니다. 그 후에는 그냥 무시됩니다.


4
이것은 받아 들인 것보다 더 나은 대답입니다. @Guill, 당신은 수락 답변을 변경해야합니다.
Nguyen Minh Binh 2012 년

5
7000 라인 템플리트 헤더 파일에서 4 #include초를 #imports로 변경 한 후 컴파일 및 XCode 인텔리전스 응답 성이 눈에 띄게 향상되었습니다. (나는 그것을 상상하고 있다고 생각하지 않습니다)
bobobobo

62

나는 Jason에 동의합니다.

나는 이것을하고 잡혔다 :

#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> :
    아닙니다. <import.h>의 일부만 이미 포함되어
    있지만 #import와 관련하여 해당 파일은 이미 완전히 포함되었습니다.

결론 :

C / C ++ 헤더는 전통적 으로 다른 포함 파일의 일부 를 포함합니다.
C / C ++ 헤더의 경우 #include를 사용하십시오.
objc / objc ++ 헤더의 경우 #import를 사용하십시오.


1
clang에는이 정의되지 않은 문제가없는 것 같습니다.
ooops 2012

23

#includeC처럼 작동합니다 #include.

#import이미 포함 된 헤더를 추적하고 컴파일 단위로 헤더를 두 번 이상 가져 오는 경우 무시됩니다. 따라서 헤더 가드를 사용할 필요가 없습니다.

결론은 #importObjective-C 에서만 사용 되며 헤더가 두 번 이상 무언가를 가져 오는 경우 걱정하지 마십시오.


2
C #include에 익숙하지 않은 분을 척하면서 (주로 내가 모르기 때문에) #include와 #import의 주요 차이점은 무엇입니까? 또한 헤더 가드가 무엇인지 말해 줄 수 있습니까?
Ryan Guill

@Ryan : Sven의 답변을보십시오.
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_MODULESin Xcode- in)를 전달하십시오 . 위에서 언급했듯이이 전략은 ANY와 ALL을 제거 LDFLAGS합니다. 에서처럼 "링크"단계는 물론 "OTHER_LDFLAGS"설정을 제거 할 수 있습니다.

여기에 이미지 설명을 입력하십시오

컴파일 / 실행 시간이 훨씬 더 "더 느리게"느껴지거나 (또는 ​​"링크"하는 동안 지연 시간이 줄어 듭니까?) 빌드 설정을 해당, GCC_INCREASE_PRECOMPILED_HEADER_SHARING, GCC_PRECOMPILE_PREFIX_HEADER, 및 GCC_PREFIX_HEADER

또한 문서화가 잘되어 있지는 않지만… module.map자신 만의 프레임 워크를 만들고 같은 편리한 방식으로 포함시킬 수 있습니다. 이러한 기적을 구현하는 방법에 대한 예제는 ObjC-Clang-Modules github 저장소를 살펴보십시오.


4

C ++과 매크로에 익숙하다면

#import "Class.h" 

비슷하다

{
#pragma once

#include "class.h"
}

이는 앱이 실행될 때 클래스가 한 번만로드됨을 의미합니다.


#pragma를 한 번만 지원합니까? 나는 항상하는 데 필요한 프라 그마 생각 내부 포함하여 에드 작업에 파일을.
uliwitness

@uliwitness 당신이 맞습니다. #pragma once포함을 수행하는 파일이 아니라 포함 된 파일에 배치됩니다. -1입니다.
herzbube

1

경우에 .h따라 문제를 일으키는 파일 중 하나에 전역 변수가 extern있고 앞에 추가하여 문제를 해결할 수 있었습니다.


0

.h 파일에 파일을 두 번 #include하면 컴파일러보다 오류가 발생합니다. 그러나 #import 파일을 두 번 이상 가져 오면 컴파일러에서이를 무시합니다.


8
#include동일한 파일을 두 번 사용 하면 오류가 발생 하지 않습니다 .
kennytm

1
@KennyTM의 의견을 보완하기 위해 동일한 헤더에 동일한 파일을 두 번 포함하면 # 일반적인 헤더 헤더 (#ifndef FILE_NAME_H #define FILE_NAME_H #end)가 있으면 컴파일 오류가 발생하지 않습니다 . 이것은 연습입니다. #import를 사용하면 헤더 가드가 필요하지 않습니다.
jbat100

@ jbat100 : #include단순히 복사하여 붙여 넣기 메커니즘입니다. #include"X 매크로"와 같은 포함 가드없이 의도적으로 한 번 이상 사용 합니다.
kennytm

파일을 두 번 포함하면 포함하는 내용에 따라 오류 발생할 수 있습니다. #include일종의 템플릿을 구현하는 데 사용되는 C 코드를 보았습니다 . 그들은 #define헤더를 포함하여 #undefa를 수행했고, redid를 다시 사용 #define하여 동일한 헤더를 두 번 포함했습니다. 이로 인해 정의 값이 다르기 때문에 코드가 매개 변수화되고 유효하며 두 번 포함되었습니다. 따라서을 사용 #include하면 이점이 있지만 C ++ 또는 ObjC와 같은 최신 언어를 사용하는 경우 일반적으로 필요하지 않습니다.
uliwitness

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 .hor .m]

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.