Calling C from Objective C - objective-c

I'm new to objective c & c. I'm trying to use this random generator c library in an objective c program. My understanding is that objective c is a strict superset of c so this should be possible.
My code compiles and runs but I get a lot of warnings.
warning: implicit declaration of function 'mt_seed32'
warning: implicit declaration of function 'mt_lrand'
warning: Semantic Issue: Implicit declaration of function 'mt_seed32' is invalid in C99
warning: Semantic Issue: Implicit declaration of function 'mt_lrand' is invalid in C99
warning: Semantic Issue: Incompatible integer to pointer conversion initializing uint32_t * (aka unsigned int *) with an expression of type int
I have not imported the C header file to the objective c class - it just finds it. If I import it I get duplicate method errors.
C library header file:
extern void mt_seed32(uint32_t seed);
extern uint32_t mt_lrand(void);
Code to call it: [I've tried calling it with [self method()] but that crashes
mt_seed32(3);
uint32_t *i = mt_lrand();
Can anyone tell me how too get rid of these warnings?

The last compiler error happens because mt_lrand(); returns an int, not a pointer to an int. Therefore, the last line should be
uint32_t i = mt_lrand();
All the other errors are due to the fact that you did not #include the library header. Could you please post the errors that occur when you do include the library header?

Messages such as implicit declaration of function 'mt_seed32' usually pop up, when you use a function before it was defined. See example.
void foo() {
//do stuff
bar(); //call bar that was declared later
}
void bar() {
...
}
This may happen if you forgot to include the header file, or you included it after you used functions declared in that header file. Another fix is to declare a function prototype before usage.
Also you assign your random number to a pointer to uint32_t. Is this what you really want?
If not, then you must remove * from your declaration: uint32_t i = mt_lrand();

Was able to fix my problem by changing file type from '.m' to '.mm'. This causes the compiler to use obj c++ not obj c. It removes the warnings but I'm not sure if I've fixed the underlying issues
Solution – Duplicate Symbol

Related

No matching function for call to pthread_create Objective-C ARC conversion

converting my project to ARC but says it can't due to the following error 'No matching function for call to pthread_create'. Here is the code it falls in, happens specifically on the line starting with pthread create. How can I fix this? It also says Candidate function not viable: no known conversion from 'NSString *' to 'void * _Nullable' for 4th argument in the sidebar underneath the error.
I've cut off the rest of the function but can provide more detail if necessary.
void World::loadWorld(std::string name)
{
if(doneLoading==0)
{
doneLoading=1;
Resources::getResources->stopMenuTune();
if(LOW_MEM_DEVICE)
{
menu->deactivate();
Resources::getResources->unloadMenuTextures();
terrain->allocateMemory();
terrain->loadTerrain(name,TRUE);
doneLoading=2;
hud->fade_out=1;
}
else
{
terrain->allocateMemory();
pthread_t foo;
pthread_create(&foo,NULL,loadWorldThread, nsstring(name));
}
}
As your error message indicates the 4th argument to pthread_create is of type void *. Under ARC you cannot simply pass an Obj-C object reference as a void * as ARC would is not able to track the reference once it is stored in a C(++) pointer variable, and therefore cannot manage the object's memory.
For situations where an Obj-C reference must be passed into the C(++) world a bridge cast can be used to inform ARC how the memory should be managed. However in your case there a better way, just pass the C++ pointer, name, without creating an NSString. If loadWorldThread expects a std::string that is the correct thing to do anyway. If it expects an NSString * then either:
modify it to take a std::string and do any required conversion to NSString * within it; or
write a small intermediate function which takes a std::string, produces an NSString * from it, and then calls loadWorldThread. Pass this new function to pthread_create.
Doing either of the above avoids the use of a bridge cast in the pthread_create call to move the Obj-C reference into the C(++) world and out of ARC control; and another bridge cast in loadWorldThread (or intermediate function as above) to move it back into the Obj-C world and into ARC control.
Addendum
Expanding on the last paragraph, as the method there seems better suited to your situation. First, it is assumed that your code:
nsstring(name)
takes a value of type std::string and returns a value of type NSString, if it does not then look up how to do this conversion.
After the above expression you have a reference to an NSString under ARC control. You cannot simply pass such a reference as a void *, you must take it out of ARC's control first and take responsibility for its memory management (but not for long as you will see). You can bridge cast your NSString * to a CFStringRef:
CFStringRef cfName = (__bridge_retain CFStringRef)nsstring(name);
You can now pass cfName, which is a reference to a heap-allocated CFString, as a void *.
Now in loadWorldThread; which should be declared to take a void *, something like void loadWorldThread(void *arg) { ... }; you need to bridge cast your CFStringRef back to NSString * and hands responsibility for its memory management back to ARC:
NSString *nsName = (__bridge_transfer NSString *)arg;
The above is a standard pattern to pass an ARC controlled reference though an anonymous reference (void *).
(Note: the above uses CFStringRef to make it clear that you are passing around a reference to a manually managed CFString, you can cast directly to void * and back again, indeed you will notice that when casting back arg was not first cast to a CFStringRef to demonstrate this.)
HTH

Marshall object attribute generates compiler error

I'm working on a brigde class to work with a unmanaged c++ library. I've a problem with the following (reduced) example code:
ref class ManagedClass
{
private:
UnManagedClass* m_UnManaged;
String^ m_someString;
public:
UserAgent_Managed(String^ someString)
{
m_someString = someString;
// Compiler error
// Severity Code Description Project File Line Suppression State Error C2665 'msclr::interop::marshal_as': none of the 3 overloads could convert all the argument
// types
std::string unManagedString = msclr::interop::marshal_as<std::string>(m_someString);
// Following works
// std::string unManagedString = msclr::interop::marshal_as<std::string>(someString);
m_UnManaged = new UnManagedClass(unManagedString);
}
};
When I call std::string unManagedString = msclr::interop::marshal_as<std::string>(m_someString); with the object attribute m_someString, the compiler tells me that there is no matching marshal_as method signature. If I perform the same with the someStringparameter the compiler doesn't throw an error. What am I missing? Both m_someStringand someString have the type String^.
Thx
The marshal_as() function is not very friendly, it is missing an overload to allow this code to compile. You can hone down the problem by looking at the IntelliSense popup that shows which overloads are available. The one you are trying to use is the 4th:
std::string marshal_as<std::string, System::String^>(System::String^ const & _from_obj)
The devil is in &, an unmanaged reference. Yes, an unmanaged reference to a managed object reference, mind blown :) But perfectly legal in C++/CLI, at runtime this argument turns into a raw pointer to the object reference.
It would have compiled if the template offered a System::String^ % _from_obj overload. It doesn't. The distinction between % and & matters a lot in C++/CLI, % declares a managed reference. Called a "tracking reference" in the docs. One that the garbage collector knows about and can update when it compacts the GC heap. Otherwise semantically completely identical to an unmanaged reference.
That the GC cannot update a & reference is the hang-up here. The compiler outright forbids generating unmanaged pointers to members of a managed type, other than through pin_ptr<>. It is far too dangerous, the garbage collector can kick in any time, even while the marshal_as() function is executing. Triggered by, say, another thread that allocates objects. And move the ManagedClass object, invalidating any raw pointers to the object. Having the function continue to use the outdated pointer at runtime will make the function produce garbage and possibly corrupt the GC heap.
The someString object reference is very different, it is stored on the stack or a processor register and cannot change when a collection occurs. So no complaints from the compiler.
You already have a good workaround here, the constructor argument is good as-is. But usually you have to provide one explicitly and store the member value into a local variable. In other words, write something like this:
auto temp = this->m_someString; // Intentional temporary
auto str = marshal_as<std::string>(temp);

Why can I assign a C block to an incompatible typedef in LLVM compiler/Xcode?

I am working on an iOS app and then I've realized that I was making a serious error when assigning C blocks to a typedeffed block pointer type with incompatible signature.
Here is the weird part: it doesn't give any errors or warnings, compiles, and runs perfectly.
Here is my typedef:
typedef void (^ULAction)();
Any ULAction object should be a C block that takes no arguments, and returns no value. I've forgotten about the signature, and at some point in my app, by mistake, I have many assignments like this:
ULAction preAction = ^(id result){
//just some code that uses the variable 'result'
[[NSNotificationCenter defaultCenter] ...];
};
The signature of the C block and the type don't match, but the code runs perfectly. I don't get any warnings or errors. The variable result is used, valid, and doesn't crash in any way. It just works.
I wonder why this is the case.
An empty parameter list means you can pass any number of parameters.
I think things would be different if you defined the block as:
typedef void (^ULAction)(void);
// ^^^^

ARC Error on UIImageJPEGRepresentation

Been battling this one for a while. Basically, I am converting an image into NSData so I can send it to a server. The code I have used before, but for some reason I am getting an ARC error on this. The error lands on the line I declare the imageData variable.
NOTE: myImage is handed to the method.
- (void)uploadImage:(NSImage *)myImage {
NSData *imageData = UIImageJPEGRepresentation(myImage, 1.0);
// Do something...
}
I get an error and two warnings
Error: Implicit conversion of 'int' to 'NSData *' is disallowed with ARC
Warning: Implicit declaration of function 'UIImageJPEGRepresentation' is invalid in C99
Warning: Incompatible integer to pointer conversion intializing 'NSData * __strong' with an expression of type 'int'
Any ideas?
You might need to include the relevant header:
#import <UIKit/UIKit.h>
Prior to C99, if you call a function that the compiler hasn't seen a declaration for, it will compile the call as if the function was declared as int UIImageJPEGRepresentation(). C99 doesn't allow that, but it seems that the compiler is still applying the old interpretation (or the compiler is in pre-C99 mode; I'm not sure what the default is), hence the ARC error.

Call Static Method with C Syntax in Obj-C?

I could redo this method using proper Obj-C syntax, but I was wondering how to call this from Obj-C. The method looks like this
#interface YarMidiCommon : NSObject
static
MIDIPacketList *makePacketList(Byte *packetBuffer, const UInt8 *data, UInt32 size);
#end
but I have no idea how to call that method. I have tried
Byte packetBuffer[size+100];
MIDIPacketList *packetList = makePacketList(packetBuffer, bytes, size);
but the error is "has internal linkage but is not defined." Is this possible without resorting to "proper" Obj-C syntax?
For the record, the method that I want to emulate would be something like
+ (MIDIPacketList*) makePacketListWithPacketBuffer:(Byte*)packetBuffer data:(const UInt8 *)data size:(UInt32)size;
which is verbose and annoying, seeing as everything here is C anyway.
This is related to this other answer I got today.
Since the function is a C function you need to remove the static keyword or else it will not be visible outside of its translation unit. Once you do that the first example you have will work. Also since it is a C function placing its declaration inside or outside of the #interface and definition inside or outside of the #implementation makes no difference on how you will call it.
Consider the declaration as being equivalent to static C function in the global scope. This is much unlike C++ or Java. There is no class scope or external linkage for this function.
As such, the #interface scope would not be a good place to declare makePacketList. The message means the definition is not visible when you use it.
You need to move the function to the .m (makes sense if you use it from this file only) or remove the static keyword.