Как определить компилятор C ++ с макросом в Xcode? - PullRequest
4 голосов
/ 15 апреля 2011

Я смешиваю исходные файлы Objective-C (* .m) и Objective-C ++ (* .mm) в проекте iOS. Когда я импортирую файл заголовка C ++ в файл * .m, как я могу исключить специфичный для C ++ код в файле заголовка? Я хочу использовать макрос компилятора, что-то вроде:

// SomeClass.h - a file I want to import in C++ and Objectice-C classes

#if CPLUSPLUS
#import "CPlusPlusLibrary.h"
#endif 

@interface SomeClass : BaseClass
{

#if CPLUSPLUS
  CPlusPlusClass* variable;
#endif    

}

@end

Ответы [ 3 ]

8 голосов
/ 02 декабря 2015

Это может плохо произойти, потому что экземпляр SomeClass будет иметь другой размер и компоновку в зависимости от того, скомпилирован ли он из файла .m или .mm.

Вот что я хотел бы сделать (с добавленным кодом, чтобы сделать его включаемым также из .c и .cp):

#ifdef __OBJC__
    #import <Foundation/Foundation.h>
#endif

#ifdef __cplusplus
    #include "CPlusPlusLibrary.h"
#endif

#ifdef __cplusplus
    class CPlusPlusClass;
#else
    typedef struct CPlusPlusClass CPlusPlusClass;
#endif

#ifdef __OBJC__
    @class AnotherObjCClass;
    @interface SomeObjCClass : NSObject
    {
        CPlusPlusClass* _variableCPP;
        AnotherObjCClass* _variableObjC;
    }
#else
    typedef struct ObjC_AnotherObjCClass AnotherObjCClass;
    typedef struct ObjC_SomeClass SomeObjCClass;
#endif

#ifdef __cplusplus
extern "C" { // Callable from C
#endif   
    void CFunctionTakingCPlusPlusClass(CPlusPlusClass* foo);
    void CFunctionTakingSomeObjCClass(SomeObjCClass* foo);      
#ifdef __cplusplus
}
#endif

Обратите внимание, что при компиляции файла .mm определяются и __OBJC__, и __cplusplus. #include и #import примерно эквивалентны в Objective-C (расширенный набор C-99), но вы должны использовать #include для всего, что видно в C / C ++.

Помните, что в C struct foo* с foo, который никогда не определен (указатель на анонимную структуру), является совершенно допустимым типом, так что это делает typedef "другие языковые классы" как анонимные структуры, которые вы можете передавать по указателю w / o глядя на содержимое.

Я оставлю в качестве упражнения, как это взаимодействует с ARC для переменных экземпляра ObjC. (Там могут быть драконы и / или вам может понадобиться __unsafe_unretained)

IIRC, если вы используете то же имя для структуры, что и класс C ++, отладчик покажет правильную информацию, если она у него есть. Я не уверен, что это безопасно для Obj-C, поэтому я использовал другое имя.

Кроме того, старайтесь избегать включения заголовка C ++ (просто #include его в вашем файле реализации .mm), если он не нужен для типов, отличных от анонимного класса. В качестве альтернативы вы можете создать для него заголовок-обертку, который выглядит как верхняя часть этого файла.

HTH, -Steve

3 голосов
/ 15 апреля 2011

Objective-C ++ - вирусная вещь, которую вы не можете остановить. Ваш текущий пример дает разным частям вашего кода (C и C ++) различное представление о макете вашего класса, и хотя я думаю, что он все еще будет работать, я уверен, что это не очень хорошая вещь.

При работе над проектами ObjC, взаимодействующими с C ++, я обычно стараюсь избегать ссылок на C ++ в моих заголовочных файлах. Это делает заголовочный файл действительным как для Objective-C, так и для Objective-C ++. Если я не могу избежать этого, то я не пытаюсь бороться с этим (это безнадежное дело); но я стараюсь не включать этот заголовочный файл ObjC ++ в «нормальные» заголовки ObjC, и вместо этого я использую директиву @class (@class SomeObjCPPClass; вместо директивы #import "SomeObjCPPClass.h"), если мне нужно сослаться на класс. Затем я включаю заголовок из файла реализации, который должен быть ObjC ++, но по крайней мере он не будет распространяться оттуда.

РЕДАКТИРОВАТЬ Последние версии Clang (2012 и более поздние версии) позволяют объявлять поля на стороне @implementation. Это может эффективно освободить ваш заголовок от любых ссылок на C ++ и сделать Objective-C ++ намного более управляемым (и менее вирусным). Чтобы сохранить пример OP, у вас теперь будет:

// SomeClass.h - a file I want to import in C++ and Objectice-C classes

@interface SomeClass : BaseClass

// (no fields)

// (methods)

@end

// SomeClass.mm
#import "CPlusPlusLibrary.h"

@implementation SomeClass
{
    CPlusPlusClass* variable;
}

// (method implementations)

@end

Это делает заголовок SomeClass.h безопасным для включения в чистые файлы Objective-C и Objective-C ++.

1 голос
/ 15 апреля 2011

Существует предопределенный макрос, который определяется при компиляции как c ++: __cplusplus Полагаю, то же самое верно для цели c ++.

...