Good day, masters. Suppose I have a java class A:
class A {
public A() {}
public native void setValue(String value);
public native String getValue();
}
When implementing the native C code, a global char[] variable is used to store the value just be set by native setValue method. The getValue method just return that global char[] variable.
Here comes my question: I create several A objects, and invoke their respective set/get method, I found that they end up writting and readding the same block of memory! Actually the global char[] variable in C native code is totally shared by all A object.
Can anybody give me some in-depth explaination of this behavior? I knew I had a fundmental misunderstanding in terms of the way JNI works. Thanks!
The problem is that you have the object oriented java on the one side, and the procedural C on the other side. When a java class A is loaded, JNI does not somehow create an object in the C world (this is C - not C++), there is no object-to-object mapping. So JNI loads the corresponding CPP file in the C world once into memory (this is completely normal behavior in C). The compiler sees a bunch of functions and a global reference, there is no need to create multiple instances somehow. When loading a Java class, all the JNI compiler does is to add the C file to the list of files to be compiled.
What you would like to have is a mapping between Java objects and C objects. This can be achieved in several ways, I suggest you read about the proxy pattern in JNI.
To explain very shortly, you have two fundamental ways to achieve this. You can either do it on the C side or on the Java side. When storing the relationship in the C world, you would maintain a hashtable in C where C objects map to Java objects. The other way around, you would have an int object in a Java object that is actually a pointer to a C object in memory. In the C code you would then dereference this pointer (through GetIntField()) and cast to the C object you require.
Of course adding
private String value;
to your Java class A, would indeed work very smootly. Java has a notion of objects, so you could access those Strings from the C world with
env->GetObjectField(obj, "value", "Ljava/lang/String;")
with env being the JNI environment.
Related
---Context---
I want to have a class called "fileProcessor". This class is completely static and merely serves as a convinient namespace (within my normal library namespace) for some global function. This is a basic blueprint of the class with only the relevant stuff
class fileProcessor{
private:
lua_State* LUA_state;
public:
static std::variant<type1,type2> processFile(const char* filePath,const char* processorScript);
}
Please note again that I ommitted most of the stuff from the class so if anything seems odd ignore it.
What process file is supposed to do is:
Read the filePath file, storing all directives including it (this is my own filetype or style of syntax. This is already handeled correctly). The directives are stored with strings, one for the command and one for everything after it.
Read the script file and check if it has a commented out fileProcessor line at the top. This is to make sure that the lua script loaded is relevant and not some random behaviour script
Load and compile the lua script.
Make all read directives available (they are saved in a struct of 2 strings as mentioned before)
Run the file and recieve a object back. The object should only be of types that I listed in the return type (variant)
I am having problems with step 4 and one vital part of the scripting.
---Question---
How can I make the creation of a full new object of type1 or type2 possible within lua, write to it from within lua and then get it back from the lua stack into c++ and still know if its type1 or type2?
---No example provided since this question is more general and the only reason I provided my class is for context.---
It seems like you are trying to do it the other way around. I quote a part of this answer:
...you are expecting Lua to be the primary language, and C++ to be the client. The problem is, that the Lua C interface is not designed to work like that, Lua is meant to be the client, and all the hard work is meant to be written in C so that Lua can call it effortlessly.
If you are convinced there is no other way that doing it other way around you can follow the workaround that answer has given. Otherwise I think you can achieve what you need by using LUA as it meant to be.
LUA has 8 basic types (nil, boolean, number, string, userdata, function, thread, and table). But you can add new types as you require by creating a class as the new type in native C++ and registering it with LUA.
You can register by either:
Using some LUA helper for C++ like luna.h (as shown in this tutorial).
Pushing a new lua table with the C++ class (check this answer).
Class object instance is created in your native C++ code and passed to LUA. LUA then makes use of the methods given by the class interface.
I'm aware that the windows "directshow" headers have both C++ class definitions, as well as their "C" struct equivalents.
My question is, if I call into a C++ method (from C--ffmpeg in this case) and it returns me a class, how can I determine if the object passed to me passes the "is a" test for various interfaces? How can I cast it to its various interface methods? If that makes sense. (all from in straight C).
The example in question is, given ffmpeg's dshow layer: https://github.com/FFmpeg/FFmpeg/tree/master/libavdevice I have access to IPin's, now I want to cast them to IAMBufferNegotiation (if they implement that interface) like in this example: http://sid6581.wordpress.com/2006/10/09/minimizing-audio-capture-latency-in-directshow/
Thanks!
Basically, I wouldn't. What I'd do is write an adapter layer in C++ that provides a C friendly interface to the C++ framework.
If you are dealing with COM objects, then you can use QueryInterface http://www.codeproject.com/Articles/13601/COM-in-plain-C
In C++, you can attempt a dynamic cast. Let's consider a function animalAtRandom() which returns a pointer to an instance of the Animal class and you'd like to test whether it is an instance of the Dog class.
Animal *someAnimal = animalAtRandom();
Dog *rex = dynamic_cast<Dog *>(someAnimal);
if (rex == NULL)
{
// this Animal is not a Dog
}
else
{
// yay
}
In pure C, this won't be easy. The C++ compiler does some pointer arithmetic to land you at the right offset, so you're better off writing a C++ helper function instead:
extern "C" Dog *fetchFirstAnimalAsDog()
{
return dynamic_cast<Dog *>(animalAtRandom());
}
In one way I can say its not efficient until C++ provides an interface to transfer data back in a C struct.
Member arrangement inside a class is implementation defined and thus some hack to copy data of members according to some sequence fails.
However in some old hacks if you want to retrieve something like important stuff from public section of class it is suggested to do a memcpy.
memcpy(dest_c_struct,src_c_class_ret_from_function,size_define);
But it wont leave you with anything of progressive nature.
UPDATE:
The example in question is, given ffmpeg's dshow layer:
https://github.com/FFmpeg/FFmpeg/tree/master/libavdevice I have access
to IPin's, now I want to cast them to IAMBufferNegotiation (if they
implement that interface) like in this example:
Are you talking about C ?? Casting IPin interface to IAMBufferNegotiation??
If I am understanding correctly, then its not possible to cast one interface type to another interface in C. In fact there are no interfaces in C.Only way is to switch back to C++ or provide C friendly interface to FFmpeg library with your application.
I am writing code in c++. I need to support few basic data types and something like BigInt. This types will be exposed to outside world(through header file), which might also include c program.
Should I implement BigInt like data type as struct or class?
The confusion is because
1. If I implement it as class, as OO advantages, I can do all processing in class. But I may have to implement some work around for c programs
2. If I implement it as struct I need not do anything special for c programs, but I loose modularity and ease of implementation.
basically C couldn't access C++ objects, either struct/class (they're the same in C++, only differs in default visibility specifier). You have to create procedural wrapper for the C++ object (i.e. creation, method call, destruction, etc).
For creation, create a function that returns opaque pointer (in C++, this would be the object pointer). For method call, add the returned pointer (from creation function above) as one of the (typically first) parameter. For destruction it's the same as method call, but typically receives no other parameter other than the pointer above.
If you plan on using it in C, I suggest you write it in C. C++ gets along with C a million times better than C gets along with C++. Another option would be to write it in C and then provide a thin C++ wrapper that gives it an OO interface.
I want to create a Java wrapper against some third-party library with C interface. The library operates on a complex Context entity which is essentially a C++ object (C++ is used internally in that library, but API is in pure C). It would be natural to wrap this entity into a class accessible from Java. For that, a pointer to Context should be stored somewhere.
I see two options to do this:
to declare a new member on java side (as long, for example) and convert it to pointer type inside JNI methods implementation
to declare a new member in JNI header (That might be illegal if Java relies on the size of structure it gerenated for me by javah)
All the tutorials on JNI are too simple to give me a hint on how to wrap a complex entities with Java classes, any links on more verbose documentation are appreciated.
I also want to know where it is appropriate to call Context destruction function (C++ destructor inside) I don't want to use Java finalize for that as Java don't favor finalize methods and I supect there is a way to define a destruction procedure on native side.
I have a little problem with the WOsclib. Not particularly with the library, it's more the callback function. The listen to specific osc commands i have to put up some callback method like
void TheOscStartMethod::Method(
const WOscMessage *message,
const WOscTimeTag& when,
const TheNetReturnAddress* networkReturnAddress)
{
std::cout << "Got the start signal";
start.alpha = 1.0;
}
start is IBOutlet UIImageView.
But the compiler says me, that start is out of scope. If I try to access start in obj-c code, it works like it should.
How can i get my Objective C Objects into the c code or at least call a objective-c function.
Thank you
Make the file an objective C++ file with extension .mm Then you can call object C and C++ objects in the same code.
XCode will call the correct compiler from the file extension (ie adding -x objective-c++ to the compile command)
Not that C++ and objective C are different languages and do not understand each others objects so to move data between them you will need to convert the data to a C type e.g. void, char int and pointers to them.
It sounds like start is an instance variable belonging to some Objective-C object and you're trying to access it just by writing its name from a C++ object. If this is the case, it should be pretty obvious why it won't work: The C++ object doesn't know anything about start. The solution is to somehow give the C++ object a reference to the Objective-C object that owns start.
You'll have to make the start object available to your other code.
You can pass it, you can pass the portions you'll be using, you can create an API for the two code bases to use. There are other options as well, all depending on precisely how you wish to use the various objects
The Solution:
I don't know if this is the best way to do it, but it works.
There must be an empty c object, which later will become our objective c object that holds all the stuff we want to access.
static gsSearchForIp* delegate = NULL;
We must define a function to set the objective c object
void setCallbackDelegate(gsSearchForIp* del)
{
delegate = del;
}
And then call it. ( I called it in the initWithFrame method)
setCallbackDelegate(self);
Now i can call a method with [delegate methodName:firstPara] in my c++ method. In this function i have access to all my stuff that I need from the gsSearchForIp class.