Is it possible to use [[NSProcessInfo processInfo] operatingSystemVersion] from C++ or C and how do I do that?
1 Answers
In XCode and Objective-C, files with extension .mm
are treated as "mixed" in the sense that one single file can contain C++/C notion as well as Objective-C code, and that even C++/C function implementations can access Objective-C classes and send messages to them.
Such a .mm
-files can then provide a trampoline function, i.e. a C-style function that is exposed and can then be used in pure C++/C-files (extension .cpp
, where Objective-C code must not occur).
Let's consider the following setting:
- A mixed file
ProcessInfoProvider.mm
, which calls[[NSProcessInfo processInfo] operatingSystemVersion]
and provides the result in a C-style functionstd::string getProcessInfoVersion_C()
, - A Pure cpp-file and a corresponding hpp-file
UseProcessInfoInC.cpp/hpp
defining a classMyCppProcessInfo
, which provides aprintVersion()
-member function and which usesgetProcessInfoVersion_C
, - Some other file that instantiates
MyCppProcessInfo
and calls member functionprintVersion()
Let's start with ProcessInfoProvider.mm
:
#import <Foundation/Foundation.h>
#import <Foundation/NSProcessInfo.h>
#include <string.h>
#include <iostream>
std::string getProcessInfoVersion_C (void) {
NSProcessInfo *processInfo = [[NSProcessInfo alloc] init];
// check avaiability of the property operatingSystemVersion (10.10+) at runtime
if ([processInfo respondsToSelector:@selector(operatingSystemVersion)])
{
NSOperatingSystemVersion versionObj = [processInfo operatingSystemVersion];
char version[500];
snprintf(version, 500, "Version %ld.%ld.%ld",
(long)versionObj.majorVersion,
(long)versionObj.minorVersion,
(long)versionObj.patchVersion);
return version;
}
else
{
// Implement fallback for OSX 10.9 and below
return "?";
}
}
Note that getProcessInfoVersion_C
is a C-style function but contains objective-C code in it's implementation.
Then, pure C++ files UseProcessInfoInC.cpp/hpp
implement class MyCppProcessInfo
:
// UseProcessInfoInC.hpp:
#ifndef UseProcessInfoInC_hpp
#define UseProcessInfoInC_hpp
class MyCppProcessInfo {
public:
void printVersion(void);
};
#endif /* UseProcessInfoInC_hpp */
and
// UseProcessInfoInC.cpp:
#include "UseProcessInfoInC.hpp"
#include <iostream>
extern std::string getProcessInfoVersion_C (void);
void MyCppProcessInfo::printVersion(void)
{
std::string version = getProcessInfoVersion_C();
std::cout << version;
}
Note that these two files do not contain any Objective-C-stuff.
Finally, let's try out MyCppProcessInfo
, e.g. in a function main()
:
// File main.mm
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#include "UseProcessInfoInC.hpp"
int main(int argc, char * argv[]) {
@autoreleasepool {
MyCppProcessInfo pi;
pi.printVersion();
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

- 10,850
- 5
- 40
- 78

- 34,891
- 4
- 35
- 58
-
Great, thanks. I'll try this soon. What's the reason for char version[] being `static`? is this to service then the method returns? Is there any way for getProcessInfoVersion_C to return a value instead of a pointer? Does for example C++ std::string work in .mm? – Simon Warta Jan 11 '17 at 19:29
-
Your're welcome. There is no specific reason for using `char *` and `static`, and you can use any C++ code and datatype, e.g. `std::string`, in `.mm`. I adapted the code to use `std::string`. – Stephan Lechner Jan 12 '17 at 11:17
-
Thanks again for the great answer. I sucessfully implemented it. While doing that I found that you need a runtime availability check when the code runs on OS X 10.9 or below. I added this check to the answer and hope you don't mind. I hope I did not mess up the code because my objective-c foo is very poor. Let me know if there is an issue in the part I changed. – Simon Warta Jan 16 '17 at 12:48