В чем разница между #import и #include в Objective-C? - PullRequest
373 голосов
/ 13 января 2009

В чем различия между #import и #include в Objective-C, и есть ли моменты, когда вы должны использовать один над другим? Один устарел?

Я читал следующий учебник: http://www.otierney.net/objective-c.html#preamble и его параграф о #import и #include, кажется, противоречит сам себе или, по крайней мере, неясен.

Ответы [ 9 ]

343 голосов
/ 18 сентября 2010

В отношении препроцессора, похоже, много путаницы.

Что делает компилятор, когда видит #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. Это выглядит так:

 #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 заменяется содержимым именованного файла только при первом обнаружении. Каждый раз после этого это просто игнорируется.

335 голосов
/ 13 января 2009

Директива #import была добавлена ​​в Objective-C как улучшенная версия #include. Однако все же вопрос о том, улучшился он или нет, все еще остается предметом дискуссий. #import гарантирует, что файл будет включен только один раз, чтобы у вас никогда не возникало проблем с рекурсивными включениями. Однако большинство приличных заголовочных файлов в любом случае защищают себя от этого, так что это не так уж и полезно.

По сути, вам решать, что вы хотите использовать. Я склонен #import заголовков для вещей Objective-C (таких как определения классов и тому подобное) и #include стандартные вещи C, которые мне нужны. Например, один из моих исходных файлов может выглядеть так:

#import <Foundation/Foundation.h>

#include <asl.h>
#include <mach/mach.h>
61 голосов
/ 18 ноября 2010

Я согласен с Джейсоном.

Меня поймали на этом:

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

Для GNU gcc он постоянно жаловался, что функция time () не определено.

Итак, я изменил #import на #include, и все прошло нормально.

Причина:

Вы #import :
включает только часть из

Вы #import

Итог:

Заголовки

C / C ++ традиционно включают частей других включаемых файлов.
Так что для заголовков C / C ++ используйте # include.
Для заголовков objc / objc ++ используйте # import.

22 голосов
/ 13 января 2009

#include работает так же, как C #include.

#import отслеживает, какие заголовки уже включены, и игнорируется, если заголовок импортируется более одного раза в единицу компиляции. Это делает ненужным использование охранников заголовка.

Суть в том, что просто используйте #import в Objective-C и не беспокойтесь, если ваши заголовки импортируют что-то более одного раза.

13 голосов
/ 18 апреля 2014

Я знаю, что эта ветка старая ... но в "современные времена" .. существует гораздо более совершенная "стратегия включения" через модули @import clang - это часто упускается из виду ..

Модули улучшают доступ к 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 aka CLANG_ENABLE_MODULES in Xcode - во время компиляции. Как упомянуто выше .. эта стратегия устраняет ЛЮБОЕ и ВСЕ LDFLAGS. Например, вы можете УДАЛИТЬ любые настройки «OTHER_LDFLAGS», а также любые фазы «Связывания».

enter image description here

Я считаю, что время компиляции / запуска «чувствуется» намного быстрее (или, возможно, просто меньше задержки при «связывании»?) .. а также, предоставляет отличную возможность удалить теперь посторонний Project-Prefix.pch файл и соответствующие параметры сборки, GCC_INCREASE_PRECOMPILED_HEADER_SHARING, GCC_PRECOMPILE_PREFIX_HEADER, GCC_PREFIX_HEADER и т. д.

Кроме того, хотя они недостаточно документированы ... Вы можете создавать module.map s для своих собственных фреймворков и включать их таким же удобным способом. Вы можете взглянуть на мой репозиторий ObjC-Clang-Modules github для некоторых примеров того, как реализовать такие чудеса.

4 голосов
/ 18 октября 2012

Если вы знакомы с C ++ и макросами, тогда

#import "Class.h" 

похож на

{
#pragma once

#include "class.h"
}

, что означает, что ваш класс будет загружен только один раз при запуске приложения.

1 голос
/ 10 августа 2015

В некоторых случаях у меня была глобальная переменная в одном из моих .h файлов, которая вызывала проблему, и я решил ее, добавив extern перед ней.

1 голос
/ 16 июля 2010

Если вы #include файл два раза в .h файлы, чем компилятор выдаст ошибку. Но если вы # импортируете файл более одного раза, компилятор проигнорирует его.

0 голосов
/ 02 декабря 2009

#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 раз в свой код, это внутри него не будет повторно объявлено.

...