16

I don't know if this is possible, but having code in plain C, is it possible to call Cocoa API's from it?
Something like #include <cocoa.h>, add the corresponding library and go for it?

Thanks for the help

Mr Aleph
  • 1,887
  • 5
  • 28
  • 44

2 Answers2

18

If you link against the Cocoa or Foundation frameworks, you can use objective-c within your C code. However, if you want to use the normal messaging syntax, you will have to change the file extension from .c to .m so that it is compiled as objective-c. If you keep the .c extension, you will only be able to use the c-style runtime calls to interact with objective-objects (i.e. objc_msgSend, objc_getClass, etc.).

Examples: Within a .m file

void cFunction() {
    [[NSString alloc] init];
}

Within a .c file

void cFunction() {
    void* cls = objc_getClass("NSString");
    void* obj = objc_msgSend(cls, NSSelectorFromString(CFSTR("alloc")));
    obj = objc_msgSend(obj, NSSelectorFromString(CFSTR("init")));
}

If you choose the second method, see the Objective-C Runtime Reference.

ivarne
  • 3,753
  • 1
  • 27
  • 31
ughoavgfhw
  • 39,734
  • 6
  • 101
  • 123
  • 5
    In general, calling `objc_msgSend` as-is is the wrong thing. You should cast it to an appropriate function type: `typedef CFStringRef (*StringWithStringIMP)(id, SEL, CFStringRef); CFStringRef string = ((StringWithStringIMP)objc_msgSend)(objc_getClass("NSString"), sel_getUid("foo"), CFSTR("This is pointless."));` – Jens Ayton May 05 '11 at 17:42
  • Cool. How do I do this? How do I link against the Cocoa or Foundation framework? is it at project level? can I `#include` it? I would like to continue to have just plain C files and a Makefile to compile it and link it (not relying on XCode to do it) – Mr Aleph May 05 '11 at 17:47
  • 1
    @MrAleph You will need to tell GCC to link against the framework. Use `-Xlinker -framework -Xlinker Foundation` to do this. You should do `#include ` to get the current runtime header. – ughoavgfhw May 05 '11 at 18:06
  • 3
    @MrAleph: I strongly recommend against using `objc_msgSend` from `.c` file. Just use `.m`. You can compile an `.m` file without XCode, by using `gcc foo.m -o foo.o -framework Foundation -framework Cocoa` etc. – Yuji May 05 '11 at 23:21
5

Objective-C is a very thin wrapper on top of C. The compiler just translates

 [obj message:argument];

into a C-call

 obj_msgSend(obj,@selector(message:),argument);

and that's it (where @selector(message:) is a magic encoding turning a selector (method name) into a computer-understandable-thingy.)

As such, there is not much difference between Objective-C and C from the compiler's viewpoint. For example, you can compile a pure C program with an Objective-C compiler, with exactly the same result as you would get by compiling with a C compiler.

So, the easiest way to "mix" a bit of Objective-C with C is to use .m extension so that the compiler use Objective-C.

That doesn't make your program suddenly very Objective-C-y. You can keep your program almost pure C, with the extension .m. With .m, you can add a few lines of Objective-C message calls without problems.

Yuji
  • 34,103
  • 3
  • 70
  • 88
  • Would I be able to write a simple Makefile to compile and link this? – Mr Aleph May 05 '11 at 17:51
  • It's really just source files with a different suffix and a different compiler call. The object files created are just plain object files like created by pure C compilers. – yeoman Jan 05 '22 at 16:06