11 ms·
OS X app in plain C
- Hydraulix989 10y agoIt's amazing and sad for computing that somehow managing to use a sane language to develop software for a very commonly used platform is seen as a serious feat of accomplishment.
- fbonetti 10y agoC is a sane language?
- nice_byte 10y agoYes.
- ddoolin 10y agoReally? I don't write systems software but it seems most here would not recommend writing in C/C++ unless it's absolutely the best choice.
- hellofunk 10y agoI don't know who you've been talking to, but that's ridiculous. C++ is one of the most widely-used languages for writing native apps for any OS. Adobe products, Chrome, anything built with Qt, even the Swift language itself, all made in C++.
- joewillsher 10y agoMost apple platform apps are written in mostly objc or Swift and not C++, I wouldn’t say it is one of the most widely used languages on these platforms by any means. The Cocoa SDK exposes an objc interface so many system framework calls have to use swift or objc. Secondly, compilers are a very different programming task to developing GUI apps; the Swift team choosing to use it has nothing to do with Apple’s assessment of how you should write an application—Apple are the people who have been leading objc development (they own the objc IP) in the last 10 years and use it in all first party apps and many system frameworks.
- dmytroi 10y agoIt depends, most of important and heavy lifting stuff in Apple platform, aka Core frameworks, are written in C, for example a quote from Core Text documentation [1]: > Many of the low level libraries in OS X and iOS are written in plain C for speed and simplicity. And don't forget that OSX/iOS are based on Darwin BSD, where most of heavy lifting is done by programs written in C. - [1] https://developer.apple.com/library/mac/documentation/StringsTextFonts/Conceptual/CoreText_Programming/Overview/Overview.html https://developer.apple.com/library/mac/documentation/String...
- joewillsher 10y agoYeah, I still wouldn’t say that c++ is “one of the most widely-used languages for writing native apps” for OS X. And internally apple use other languages a lot, but frameworks like UIKit, AppKit, and many of the other public frameworks they expose in the SDK are objc, with foundation for example abstracting a lot of CoreFoundation C code.
- izacus 10y agoIs there an actual half-popular production app for OS X written in Swift yet?
- astrange 10y agoProbably not, but Lyft is an iOS app written in Swift.
- hellofunk 10y agoPerhaps most smaller apps, yes. And some big ones too. But a very significant percentage of the commercial software industry writes apps for OSX in C++, including Autodesk, Adobe, many major games written using engines like Unreal and Unity (which also support other languages), etc. That's not a knock against anyone who does or doesn't write apps in a particular language; but folks should know what the reality is, and Objective C or Swift are by no means the only or even necessarily the most profitable ways to writes apps for OSX, though those languages are perfectly fine for many circumstances.
- ssalazar 10y ago> Adobe products Adobe products have codebases going back decades, of course they are written in C/C++. Furthermore most Adobe apps have fairly advanced processing needs that your run-of-the-mill CRUD GUI does not. > anything built with Qt Qt isn't even stock C++, they had to hack a meta-compiler on top of C++ to effectively serve the needs of their GUI system. > even the Swift language itself By this logic, thousands of GUI apps are written in x86 assembly. Between C#, Objective-C, Swift, JS+Electron, Mono, and many other mature, high-level frameworks that don't trash memory at the slightest provocation, youd need some very good reasons to use C or C++ for a GUI app these days.
- chillingeffect 10y agoThis is a very particular crowd, largely into web software and ecosystems for rapid growth of SaaS. I wouldn't extrapolate this crowd into software languages in general. You should always use the best tool for the job. Many people write quite excellent software in C/C++ every day. Just as many people use chainsaws, drive cars, fire guns and take pills every day. These are all productive activities with low floors and high ceilings. Anyone can jump in and make a mess. It takes care and attention to do them well.
- jimjimjim 10y agoagree. If this was an enterprise/cio/it/gov discussion web site then all the conversations would be java and .net vs c++ if this was a scientific computing website then python, c/c++ and fortran and would be mentioned etc. if this was a hardware/firmware website it would be c vs (whatever black magic is used by hardware wizards).
- austinz 10y agoVHDL vs Verilog flame wars everywhere. Also, discussions on people's favorite idiosyncratic, vendor-specific dialect of C for embedded devices.
- chillingeffect 10y agoGah, this. Also noobs who want to "replace their 2,000 device-per-year microcontroller application with an FPGA so that it can someday be put onto a ASIC." They're basically vinyl hipsters who fancy themselves "EE/chip designerz" and want to immortalize themselves.
- Hydraulix989 10y agoWhy recommend Objective-C over C/C++ though? It's more or less subject to the same "pitfalls" that go against C, PLUS it is a syntactical nightmare. [whatTheHell:is this:shit]; Is ARC really that much of a savior here? At least method calls get resolved at compile time.
- ssalazar 10y ago> It's more or less subject to the same "pitfalls" that go against C Only if you write C code in Objective-C. > PLUS it is a syntactical nightmare. [whatTheHell:is this:shit]; Honestly, get over it. This is largely a surface-level detail that makes no difference once youve used the language for more than a week. I take it you have similar complaints against Ruby, Python, Lisp, or any other language that dares to break ranks with the C++/Java syntax idiom. > Is ARC really that much of a savior here? Yes, manual memory management is one of the main things that C/C++ programmers seem to consistently screw up.
- Hydraulix989 10y ago> Yes, manual memory management is one of the main things that C/C++ programmers seem to consistently screw up. There's no reason why memory management _should_ be something that C++ programmers screw up now with containers like smart_ptr and std::string. Yes, if you malloc/free stuff and use things like memcpy, you're playing with fire, but the whole point of "modern C++" is that we have better and safer alternatives. On the other hand, Obj-C message passing (which really means method calls that are resolved at runtime) is another way, like manual memory management, to really shoot yourself in the foot if you make a mistake. > I take it you have similar complaints against Ruby, Python, Lisp, or any other language that dares to break ranks with the C++/Java syntax idiom. I actually don't. Forced named parameters and "array brackets" denote method calls are arguably poor choices for syntax. On the other hand, getting rid of semicolons and enforcing whitespace a la Python is okay, and Lisp is really just an extension of RPN. The point is your point that I dislike anything by default that is "not C/C++/Java" is actually pretty incorrect. I do have opinions, but that isn't the basis through which they are formed, and quite honestly, I'm offended that you even made such an assumption about me in the first place. > Honestly, get over it. Bad advice, I'm allowed to have an opinion (and I do substantiate it above). Regardless, I have "gotten over it" given that a large portion of my day job is spent writing Obj-C, and while I do like it better than Java as a language overall (even not having to deal with JNI for interop is a dream), god help the syntax.
- codemonkeymike 10y agoC was not designed to create gui's. So its a feat of accomplishment as opening a bottle with your teeth.
- ultramancool 10y agoWindows, X11 and Gtk would argue with you.
- coldtea 10y agoWindows is written in C++ mostly. As for X11 and Gtk, well, I argue with THEM.
- q3k 10y agoYes, but WinAPI (which is all that is required to do GUI programming in Windows) is C-centric.
- coldtea 10y agoYeah, but nobody (ie. very few if anybody) does GUI programming in WinAPI, so I don't see how it's relevant in determining whether C is good for GUIs.
- ultramancool 10y agoWindows itself perhaps, but not the Windows API. If you've ever done any low-level Windows development, it's pure C. See here for a tutorial using it for basic GUI stuff: http://zetcode.com/gui/winapi/firststeps/ http://zetcode.com/gui/winapi/firststeps/ I've even seen several games that use it directly for keyboard handling and such to this day. And all the new, fancy GUI frameworks which exist on Windows are basically just wrappers on top of WinAPI.
- United857 10y agoUnless something has changed drastically since when I was at MS, the Windows kernel and the major OS DLLs is pretty much pure C. The GUI/window manager are more C++. Even Word and Excel were still C (although Office shared much C++ code in a common DLL) Gotta love legacy code from the 1980s/1990s.
- santaclaus 10y ago> For some reason if we run the app from command line than menu is not accesible by mouse at first time This happens with Qt apps on OS X, as well, and it drives me bonkers. If you launch from the command line you have to command tab away and back for the menu to work
- fit2rule 10y agoIts because of the missing .app bundle and appropriate Info.plist. I just submitted a pull request to fix this - maybe its useful for you too, check it out: https://github.com/jimon/osx_app_in_plain_c/pull/1 https://github.com/jimon/osx_app_in_plain_c/pull/1
- chillacy 10y agoStrangely this happens on my cocoa app too... but it hasn't always been the case and I've had this thing for about 5 years now, so I suspect that somewhere, something got messed up.
- santaclaus 10y agoIt started for me around on the Mountain Lion to Mavericks upgrade, so whatever changed then.
- btrask 10y agoThere was a thread the other day where people were talking about languages that were easily interoperable with the "C ABI" (although there is no such thing). Languages listed included C++, Rust, and maybe a few others--but no mention of Objective-C. The ability to use a high-level, dynamic language (ObjC), C, and even inline assembly in a single source file is unique to Objective-C (at least among the "mainstream" languages), and something I think is often under-appreciated. One comment on the code here: for message calls returning type 'id' (object type), you don't need to cast the dispatch function. It would make the code much more readable. For other return types, you need a cast, but I'd wrap it in a macro. You could even use a C11 generic macro to handle floating point return values (unfortunately necessary).
- eridius 10y agoYou do actually need to cast the dispatch function, because there is no guarantee for all platforms that the ABI for calling a variadic function is the same as the ABI for calling a non-variadic function with the same arguments.
- dmytroi 10y agoThanks for the comment! On OS X if OBJC_OLD_DISPATCH_PROTOTYPES is not defined, you will get this declaration with zero arguments: void objc_msgSend(void /* id self, SEL op, ... */ ), which is possible to call from C without cast by using implicit function declaration, but this call will fail if compiled as Objective-C code with error "too many arguments to function call", I've decided to write in a style that compiles as C and Objective-C code. PS. Would be nice to be able to use functions from clang Objective-C runtime [1], but for some reason they are not exposed in the public headers. - [1] http://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime-support http://clang.llvm.org/docs/AutomaticReferenceCounting.html#r...
- mikeash 10y agoYou should still cast the dispatch function even when your return type is id. For one, C vararg type promotion makes it impossible to pass certain types in as parameters otherwise. For example, you can't pass a float. It's also easy to make mistakes because of type mismatches. For example, if you pass `42` to a CGFloat parameter, this works fine when you cast msgSend to the right type, but will fail amusingly if you rely on varargs to make it through. Perhaps most importantly, vararg calls aren't guaranteed to be compatible with a non-vararg target (as most/all methods you call will be), and you'll see this in action on ARM64. Currently, you can #define OBJC_OLD_DISPATCH_PROTOTYPES 0 to have the compiler enforce this requirement. (This declares the functions to take (void) rather than (id, SEL, ...).) It's likely that Apple will eventually make this the default.
- sigjuice 10y agoI don't buy the "plain C" claim, given the gratuitous use of objc_msgSend().
- juliangoldsmith 10y agoWhat else would it be? objc_msgSend() is called as a C function, to interface with ObjC code.
- msbarnett 10y ago...objc_msgSend() is a plain C function that grovels around in various runtime data structures to call the correct function pointer for GUI and OS functionality. Any alternate method of finding and calling those functions would amount to simply reimplementing objc_msgSend()
- sgt 10y agoIf you compile it, you'll see that the ObjC executable with no ARC and the C-only executable are exactly the same size stripped. The ObjC version with ARC is 392 bytes bigger.
- mcmatterson 10y agoA few years ago I dove into the idea of trying to make a C only iOS app (well actually, it was a quick exploration of how hard it would be to build your own UI kit without using UIKit). The dive bottomed out pretty quickly, as I couldn't figure out a way to access windows without resorting to UIWindow methods, and `UIGraphicsGetCurrentContext()` acted super wonky calling it without 'proper' bootstrapping around it. I was expecting more, given the usual layered approach that Apple takes with their system libraries.
- eyeareque 10y agoI'm not a developer, but does it count when they use objc header files? #include <objc/objc.h> #include <objc/runtime.h> #include <objc/message.h> #include <objc/NSObjCRuntime.h>
- wtallis 10y agoI think those are all valid C header files. They just define typedefs and macros that are about ObjC, but themselves are plain C.
- tosseraccount 10y agoAs a side note: http://stackoverflow.com/questions/525609/use-c-with-cocoa-instead-of-objective-c http://stackoverflow.com/questions/525609/use-c-with-cocoa-i... A commenter at stackoverflow provides some code that "shows how to access Cocoa GUI from pure C/C++ and build a truly functional GUI application" He notes that you must "link against Cocoa framework".
- icodestuff 10y agoI don't buy it. Yes, the language may be C, but if you're linking the ObjC runtime and frameworks, all you're really avoiding here is the nib-loading machinery. To be fair, I think that's a perfectly reasonable goal in and of itself - showing how to set up an OS X app "from scratch" is definitely something I'm interested in - but we shouldn't pretend this isn't strongly relying on Objective-C to actually get things done. EDIT: indeed, the makefile copies main.c to main.m before invoking clang, which means it's using the Objective-C compiler. What would be much more impressive is if this used only the C Core* frameworks (Core Foundation and Core Graphics in particular) to do the same thing.
- hunterwerlla 10y agoSo obviously it's impossible to write a linux app in anything pure but C because the kernel is written in C. That makes no sense.
- deleted 10y ago[deleted]
- thought_alarm 10y agoLook at the makefile again. It builds five different binaries from the same source file, one of which using a C compiler. This is no different than writing a COM application in C. Both COM and objc runtimes provide similar dynamic OO services over a plain C API.
- convivialdingo 10y agoI just ran the code through clang (Apple LLVM version 5.1) with no problems. You don't have to rename the source - but perhaps there are issues in other configurations. clang -framework Foundation -framework OpenGL -framework Cocoa -o test test.c
- 0x0 10y agoRelevant: "Let's build objc_sendmsg()" https://www.mikeash.com/pyblog/friday-qa-2012-11-16-lets-build-objc_msgsend.html https://www.mikeash.com/pyblog/friday-qa-2012-11-16-lets-bui...
- chris_wot 10y agoWould love to see this annotated.
- conradev 10y agoAnd introduced in OS X 10.10 is the ability to build an OS X app in pure JavaScript: http://tylergaw.com/articles/building-osx-apps-with-js http://tylergaw.com/articles/building-osx-apps-with-js (Atwood's Law in action)
- justsaysmthng 10y agoDon't do this at home. It looks so ugly because it's dangerous and vice-versa. If you really want to write (and read) code like this: id titleString = ((id ()(id, SEL, const char))objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "sup from C"); ((void (*)(id, SEL, id))objc_msgSend)(window, sel_registerName("setTitle:"), titleString); instead of this [window setTitle:@"sup"]; then I guess it would be easier to write a Objective-C to C converter (if there isn't one already) and convert your Objective-C app into C for added coolness. I
- deanCommie 10y agoSeriously, I don't know who's downvoting you. This needs a huge "for academic purposes only disclaimer". Higher level abstractions exist for a reason.
- elsurudo 10y agoI think it's obvious that this is an academic exercise (or "just because I can" sort of thing), which makes the GP's comment quite unnecessary.
- dmytroi 10y agoOne practical example would be tigr [1] - a cross platform window framework for making simple applications, could be compiled as one header drop-in only lib. You simply cannot make it one header without making calling ObjC runtime from C. Why it's necessary to make it work as one drop-in header? Well it's a new trend in C libraries, which allows using libraries with the least resistance possible, it's like a package manager but nicer - you only have one file! Great example of modern one header libs is probably the famous stb package [2]. - [1] https://bitbucket.org/rmitton/tigr/src https://bitbucket.org/rmitton/tigr/src - [2] https://github.com/nothings/stb https://github.com/nothings/stb
- btrask 10y agoI haven't looked at tigr yet (it seems interesting!) but could you just use '#ifdef __OBJC__'?
- bdrool 10y agoThis is what Objective-C looks like if you "unroll" it to plain C. Not too surprisingly, it's very verbose. Other than as an exercise, there's no reason to do this, particularly given that Objective-C is a strict superset of C.[1] [1] http://stackoverflow.com/questions/19366134/what-does-objective-c-is-a-superset-of-c-more-strictly-than-c-mean-exactly http://stackoverflow.com/questions/19366134/what-does-object...
- beamatronic 10y agoOutstanding! I have been wanting to see this for a long time. I really want to build OS X apps but I personally prefer to build GUIs programatically.
- leonatan 10y agoSo build programmatically. But use Objective C or Swift.
- WizardlySquid 10y agoOh god that's terrifying.
- sdegutis 10y agoMy interest in this comes from wanting to build Objective-C based OSX-UIs using scripting languages that are only embeddable in C, like Lua. When (if?) that day comes, I'll be like a kid in a candy store all over again.
- dmytroi 10y agoI would recommend you to try CodeFlow from celedev [1], it's a dynamically generated Lua binding to Objective-C. Plus a nice editor with hot reloading support and other cool features. - [1] https://www.celedev.com/en/codeflow/ https://www.celedev.com/en/codeflow/
- pps43 10y agoThat's a lot of boiler plate code. Is there a way to make it smaller? For example, if all I need is to open and process a file with no GUI (maybe a progress bar).
- justinlardinois 10y agoI'm sure the Windows version would be just as bad. Most of the useful parts of the Windows API don't have a C interface, so you have to use COM, which essentially means editing vtable-like structures by hand. https://en.wikipedia.org/wiki/Component_Object_Model https://en.wikipedia.org/wiki/Component_Object_Model
- seabrookmx 10y agoYou wouldn't have to use COM for this at all. You could use the Win32 API directly, which is a C API and would be much less code. In fact I'll link a comment from above that shows this: https://news.ycombinator.com/item?id=11641545 https://news.ycombinator.com/item?id=11641545
- userbinator 10y agoI've been programming Windows GUI apps for over a decade. Most of the Windows API, i.e. Win32, is not COM. I have also used COM from C, and while it's not as pleasant as the pure Win32 API, it doesn't involve the massive amounts of function pointer casting shown here. vtables are involved but they can be defined as C structures, whereas this example seems to show objc_msgSend() returning a very large number of different possible function pointer types.
- justinlardinois 10y agoThe two replies to my comment both need a response, so I'll make this a sibling. Looks like I was wrong, and I was working harder when I wrote Windows C programs than I needed to. The Windows API documentation is sort of confusing and I got the impression that only the CRT functions have a C interface.
- mayoff 10y agoRichard J. Ross III did it a few years ago for iOS: http://stackoverflow.com/a/10290255/77567 http://stackoverflow.com/a/10290255/77567
- jheriko 10y agosorry, but mediocre at best, full of mistakes at worst. i'm sure it was a good exercise in learning objective-c but this is not an amazing achievement. i'd expect much better from someone competent reading the god awful docs and reverse engineering by inspection. don't give up though. doing things like this over and over, especially in the face of nay saying arses like me, is what makes great programmers. :)
- gcr 10y agoAs a beginner to Objective-C, I found reading the source here highly informative, because it gives you a rare peek at the actual machinery underneath everything that's going on.
- userbinator 10y agoAs someone who has done a lot of Win32 programming in plain C, I can recognise some common patterns like an event loop and window creation, but it's quite amazing how much extra "cruft" there is just to deal with what appears to be the contortions of OOP'ing everything. All those string constants are rather surprising too. The interesting thing is, the few times I've had to use a Mac the GUI didn't feel quite as responsive as Windows on the same hardware --- it wasn't jerky/stuttering, just what I'd describe as "smooth but sluggish", and the binaries were noticeably larger, and I now wonder if this increased abstraction and complexity has anything to do with it. For comparison, a similar Win32 app in plain C: http://www.winprog.org/tutorial/simple_window.html http://www.winprog.org/tutorial/simple_window.html X Windows app in plain C: http://www.paulgriffiths.net/program/c/srcs/helloxsrc.html http://www.paulgriffiths.net/program/c/srcs/helloxsrc.html ...and just for fun, the same simple Win32 app from above in Assembly language: http://win32assembly.programminghorizon.com/tut3.html http://win32assembly.programminghorizon.com/tut3.html Looking at the code again, if I were forced to write an OS X app in plain C, there would be plenty of macro usage around objc_msgSend.
- barrkel 10y agoWindows is effectively already an OO system; you "override" methods (message codes) in your window procedure, with the base implementation provided by the default window procedure. Windows even uses the terminology of window classes to describe the behaviour of window instances. Personally, I'd blame UI latency more on a deeper composition stack and rendering sophistication rather than object orientation. Unless you're using late bound method calls for pixel-level drawing primitives, they shouldn't be a significant percentage of the event dispatch loop that turns input into visual results.
- chillacy 10y agoThis example is extremely contrived, of course it's going to be a nightmare in C. GUI latency probably has little to do with the overhead of objC message sending and more to do with tuning how things respond for UX purposes. For instance it's well known among gamers that on OSX the mouse has acceleration which makes it smother but less responsive in gaming. I wouldn't be surprised if this carried over to scrolling, animations, etc. > If I were forced to write an OS X app in plain C, there would be plenty of macro usage around objc_msgSend You will have re-invented the early versions of Objective C which were all done in the preprocessor :)
- whitehat2k9 10y agoWell, that looks rather unpleasant.