В чем разница между #import и #include в Objective-C?

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

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


person Ryan Guill    schedule 13.01.2009    source источник


Ответы (10)


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

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

#import <Foundation/Foundation.h>

#include <asl.h>
#include <mach/mach.h>
person Jason Coco    schedule 13.01.2009
comment
Даже если файлы заголовков содержат средства защиты включения, при использовании #include производительность компиляции все равно снижается - компилятор должен открывать каждый файл заголовка, чтобы заметить средства защиты включения. - person Matt Dillard; 13.01.2009
comment
защита заголовка - это директива препроцессора, которая гарантирует, что заголовок включается в исходный файл только один раз. - person Jason Coco; 15.01.2009
comment
Я думаю, что #import на самом деле является дополнением GCC, а не Objective-C. Вы можете использовать его на языках, отличных от ObjC, если вы компилируете с GCC (или Clang) - person Dave DeLong; 02.12.2009
comment
@dave - #import - это дополнение Objective-C к препроцессору. GCC просто поддерживает его в исходных файлах C и C ++, хотя официально предлагает не использовать его в C или C ++ в пользу переносимых традиционных средств защиты заголовков. Однако все препроцессоры Objective-C должны включать #import. - person Jason Coco; 02.12.2009
comment
Защита заголовка - это то место, где вы добавляете вверху: #ifndef myheader #define myheader ... за которым следует код заголовка ... #endif - person Tim; 12.03.2012
comment
Итак, официальная рекомендация - избегать использования более новых, простых и лучших вещей ради сохранения совместимости со старыми вещами, которые можно так же легко обновить для поддержки нового ключевого слова? Это чепуха. Кому-то нужно привести новых чиновников. - person aroth; 24.01.2013
comment
@aroth: Дело не в том, что новее или старше. Речь идет о стандартном и нестандартном. - person Chuck; 07.03.2013
comment
@ Чак - Возможно. Но стандарт, который не развивается и рекомендует устаревшие, неуклюжие и тупые способы делать что-то, на мой взгляд, не очень ценен. Особенно, когда возможности инструментов действительно развиваются, и вдвойне, когда все препроцессоры Objective-C должны включать #import, и когда мы говорим о коде в контексте проекта Objective-C. - person aroth; 07.03.2013
comment
В приличном компиляторе защита включения не требует затрат во время компиляции. Заголовочный файл необходимо включить один раз, если вы хотите его использовать. Когда он включен, компилятор обнаружит защиту заголовка. и запомни это. Во втором #include для того же файла компилятор знает о защите заголовка и даже не смотрит на файл. - person gnasher729; 24.02.2014
comment
Это не стандартное против нестандартного; это язык против языка, и одно намерение против другого. Если вы используете Objective-C и собираетесь включить заголовок Objective-C, используйте #import. Если вы используете C, C ++ или, используете Objective-C и просто хотите встроить один файл в другой, используйте #include. - person Steven Fisher; 16.04.2014
comment
Следует также отметить, что в C ++ используется другой подход, в котором вы используете #pragma once вместо ручных средств защиты заголовков. Таким образом, C ++ по-прежнему использует #include, но также решает проблему, для решения которой предназначен #import. - person uliwitness; 12.08.2015
comment
@ gnasher729 Правильно, это называется оптимизацией с несколькими включениями и позволяет избежать файл, который нужно повторно открывать без надобности. - person Bilow; 15.12.2016
comment
Хорошая особенность #import, о которой здесь, кажется, никто не упоминает, заключается в том, что это единственное решение, не требующее дополнительного кода. В любом случае это не так много кода, но обычно лучше меньше кода для одного и того же. Также немного снижает планку для новых разработчиков, которые могут не знать о защите заголовков или #pragma once. - person William T Froggard; 15.05.2018

Кажется, существует большая путаница в отношении препроцессора.

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

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

person Sven    schedule 17.09.2010
comment
Это лучший ответ, чем принятый. @Guill, вы должны изменить принятый ответ. - person Nguyen Minh Binh; 03.01.2013
comment
После изменения 4 #includes на #imports в файле заголовка шаблона из 7000 строк наблюдается заметное улучшение производительности при компиляции и отзывчивости XCode intellisense. (Не думаю, что я это себе представляю) - person bobobobo; 13.08.2013

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

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

#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› включает только часть ‹time.h› с помощью #defines

Вы #import ‹time.h›:
Не пойдем. Несмотря на то, что уже была включена только часть ‹time.h›,
что касается #import, этот файл теперь уже полностью включен.

Нижняя линия:

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

person user512705    schedule 18.11.2010
comment
Кажется, что у clang нет этой неопределенной проблемы. - person ooops; 23.02.2017
comment
Это действительно отличный пример того, почему сложно незаметно внедрить современные функции (#import) в существующие системы. Если системные библиотеки будут обновлены, чтобы лучше обрабатывать #import ... вероятно, нет. Если бы это было так, то это было бы за счет многих существующих проектов, которые сознательно или неосознанно полагаются на существующее поведение. Если в процессе разработки языков перестанут появляться новые полезные и перспективные функции ... нет. Итак, это никогда не бывает так просто, как предполагают некоторые комментарии к принятому ответу. - person rambo; 09.08.2020

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

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

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

person Ferruccio    schedule 13.01.2009
comment
притворившись на минуту, что я не знаком с C #include (в основном потому, что я не знаком), в чем основное различие между #include и #import? Кроме того, вы можете сказать мне, что такое защита заголовка? - person Ryan Guill; 13.01.2009
comment
@ Райан: Посмотри на ответ Свена. - person Adrian Petrescu; 18.09.2010

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

Модули улучшают доступ к API программных библиотек, заменяя текстовую модель включения препроцессора более надежной и более эффективной семантической моделью. С точки зрения пользователя код выглядит немного иначе, потому что здесь используется объявление импорта, а не директива препроцессора #include:

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

or

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

Однако этот импорт модуля ведет себя совершенно иначе, чем соответствующий #include: когда компилятор видит импорт модуля выше, он загружает двоичное представление модуля и делает его API напрямую доступным для приложения. Определения препроцессора, предшествующие объявлению импорта, не влияют на предоставленный API ... потому что сам модуль был скомпилирован как отдельный автономный модуль. Кроме того, любые флаги компоновщика, необходимые для использования модуля, будут автоматически предоставлены при импорте модуля. Эта семантическая модель импорта решает многие проблемы модели включения препроцессора.

Чтобы включить модули, передайте флаг командной строки -fmodules или CLANG_ENABLE_MODULES в Xcode- во время компиляции. Как упоминалось выше .. эта стратегия устраняет ВСЕ и ВСЕ LDFLAGS. Например, вы можете УДАЛИТЬ любые настройки "OTHER_LDFLAGS", а также любые этапы "Связывание" ..

введите описание изображения здесь

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

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

person Alex Gray    schedule 18.04.2014

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

#import "Class.h" 

похож на

{
#pragma once

#include "class.h"
}

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

person Evol Gate    schedule 18.10.2012
comment
Поддерживается ли это однократное использование #pragma? Я всегда думал, что для работы прагма должна быть внутри включенного файла ed. - person uliwitness; 12.08.2015
comment
@uliwitness Вы правы. #pragma once помещается во включенный файл, а не в файл, который выполняет включение. -1 за это. - person herzbube; 22.06.2016

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

person neowinston    schedule 10.08.2015

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

person Husmukh    schedule 16.07.2010
comment
#include один и тот же файл дважды не приводит к ошибке. - person kennytm; 16.07.2010
comment
Чтобы дополнить комментарий @KennyTM, # включение одного и того же файла дважды в один и тот же заголовок не приводит к ошибке компиляции, ЕСЛИ обычные заголовки gards (#ifndef FILE_NAME_H #define FILE_NAME_H #end) есть. Это ожидаемая практика. Использование #import не требует защиты заголовков. - person jbat100; 17.12.2012
comment
@ jbat100: #include - это просто механизм копирования и вставки. #include преднамеренно используется более одного раза без включения защиты, например макрос X. - person kennytm; 18.12.2012
comment
Двойное включение файла может привести к ошибкам в зависимости от того, что вы включаете. Я видел код C, который использовал #include для реализации своего рода шаблонов. Они сделали #define, включили заголовок, #undefd и переделали #define, включили тот же заголовок во второй раз. Это привело к тому, что код был параметризован, действителен и включен дважды, поскольку значение определения было другим. Таким образом, у использования #include есть преимущества, но если вы используете современный язык, такой как C ++ или ObjC, вам это обычно не нужно. - person uliwitness; 12.08.2015

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

person Celso Dantas    schedule 01.12.2009

#include vs #import

История:

#include => #import => Precompiled Headers .pch => @import Module(ObjC); => import Module(Swift)

[Предварительно скомпилированные заголовки .pch]
[@ import Module (ObjC);]
[import Module (Swift)]

#include + guard == #import

#include guard Wiki - защита от макросов, заголовков или файлов предотвращает double включить заголовок с помощью preprocessor, что может замедлить время сборки

Недостаток #import

Работает с областью файлов, поэтому у нас медленное время сборки, потому что компилятор должен анализировать и компилировать столько раз, сколько файлов .h было импортировано в область проекта.

[#import in .h or .m]

person yoAlex5    schedule 06.12.2019