В чем разница между #import и #include в Objective-C?
каковы различия между #import и #include в Objective-C и есть ли времена, когда вы должны использовать один над другим? Один устаревший?
Я читал следующий учебник:http://www.otierney.net/objective-c.html#preamble и его абзац о #import и #include, похоже, противоречит самому себе или, по крайней мере, неясен.
9 ответов
директива #import была добавлена в Objective-C как улучшенная версия #include. Однако вопрос о том, улучшилось ли оно или нет, все еще остается предметом обсуждения. #import гарантирует, что файл включен только один раз, чтобы у вас никогда не было проблем с рекурсивными включениями. Тем не менее, большинство достойных заголовочных файлов защищают себя от этого в любом случае, поэтому это не так много пользы.
в основном, это до вас, чтобы решить, какой вы хотите использовать. Я склонен #импортировать заголовки для Objective - C вещи (например, определения классов и тому подобное) и #включают стандартные вещи C, которые мне нужны. Например, один из моих исходных файлов может выглядеть так:
#import <Foundation/Foundation.h>
#include <asl.h>
#include <mach/mach.h>
там, кажется, много путаницы в отношении препроцессора.
что делает компилятор, когда он видит #include
что он заменяет эту строку содержимым включенных файлов, без вопросов.
так что если у вас есть файл a.h
С таким содержанием:
typedef int my_number;
и С таким содержанием:
#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_
уже определены.
это работает очень хорошо, но имеет два недостатка. Прежде всего, должны быть написаны охранники include, а имя макроса должно отличаться в каждом заголовке. А во-вторых, компилятору еще нужно искать файл заголовка и читать его так часто, как он включен.
Objective-C имеет #import
инструкция препроцессора (ее также можно использовать для кода C и C++ с некоторыми компиляторами и опционы.) Это делает почти то же самое, что #include
, но он также отмечает, внутренне, какой файл уже был включен. The #import
строка заменяется только содержимым именованного файла в первый раз, когда он встречается. Каждый раз после этого его просто игнорируют.
Я согласен с Джейсоном.
меня поймали на этом:
#import <sys/time.h> // to use gettimeofday() function
#import <time.h> // to use time() function
для GNU gcc он продолжал жаловаться, что функция time() была не определен.
Итак, я изменил #import на #include, и все прошло хорошо.
причина:
вы #import
в
вы #import в:
Бесполезный. Хотя только часть уже был включен, как
что касается #import, этот файл теперь уже полностью включено.
итог:
заголовки C/C++ традиционно включают частей другие включаемые файлы.
Поэтому для заголовков C / C++ используйте #include.
Для заголовков objc / objc++ используйте #import.
#include
работает так же, как C #include
.
#import
отслеживает, какие заголовки уже включены и игнорируется, если заголовок импортируется более одного раза в единице компиляции. Это делает ненужным использование header guards.
в нижней строке просто использовать #import
в Objective-C и не волнуйтесь, если ваши заголовки заканчиваются импортом чего-то более одного раза.
Я знаю, что этот поток старая... но в "Новое время".. существует намного превосходящая стратегия "включить" через из Clang @import
модули - это часто упускается из виду..
модули улучшают доступ к API программных библиотек, заменяя текстовую модель включения препроцессора более надежной, более эффективной семантической моделью. С точки зрения пользователя, код выглядит немного иначе, потому что используется объявление импорта, а не #включить директиву препроцессора:
@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_MODULES
на Xcode
- во время компиляции. Как упоминалось выше.. эта стратегия устраняет все LDFLAGS
. Как и в, ВЫ можете удалить любые " OTHER_LDFLAGS" настройки, а также любые фазы "связывания"..
Я нахожу время компиляции / запуска, чтобы" чувствовать " себя намного быстрее (или, возможно, просто меньше отставания при "связывании"?).. а также, предоставляет отличную возможность очистить теперь уже посторонний проект-префикс.PCH-файл и соответствующие настройки сборки, GCC_INCREASE_PRECOMPILED_HEADER_SHARING
, GCC_PRECOMPILE_PREFIX_HEADER
и GCC_PREFIX_HEADER
, etc.
кроме того, хотя и не хорошо документировано... вы можете создать module.map
s для ваших собственных рамок и включают их в такая же удобная мода. вы можете взглянуть на мои ObjC-Clang-модули GitHub repo для некоторых примеров того, как реализовать такие чудеса.
Если вы знакомы с C++ и макросы, то
#import "Class.h"
похож на
{
#pragma once
#include "class.h"
}
это означает, что ваш класс будет загружен только один раз при запуске приложения.
Если вы #включите файл два раза.H-файлы, чем компилятор выдаст ошибку. Но если вы # импортируете файл более одного раза, компилятор проигнорирует его.
в мае у меня была глобальная переменная в одном из моих .h
файлы, которые вызывали проблему, и я решил ее, добавив extern
перед ним.
#include
он использовал, чтобы получить "вещи" из другого файла в тот #include
используется в.
Ex:
in file: main.cpp
#include "otherfile.h"
// some stuff here using otherfile.h objects,
// functions or classes declared inside
защита заголовка используется в верхней части каждого файла заголовка (*.h) предотвратить включение одного и того же файла более одного раза (если это произойдет, вы получите ошибки компиляции).
in file: otherfile.h
#ifndef OTHERFILE
#define OTHERFILE
// declare functions, classes or objects here
#endif
даже если вы положите #include
"otherfile.h " N время в вашем коде, это внутри него не будет быть объявленным заново.