Is there any way to pass a function pointer to an Objective C method, and then have that method modify the function pointer to point at a C function somewhere else?
Creating a method that accepts a function pointer is simple enough:
- (void)doSomethingWithFunctionPointer:(void(*)(/* args go here */))functionPointer;
I can then call that function inside doSomethingWithFunctionPointer simply by calling:
if (functionPointer)
{
functionPointer();
}
But what if I actually wanted to change the functionPointer to point at something else within doSomethingWithFunctionPointer, so that any code outside that method can then call the changed function pointer to call the function that doSomethingWithFunctionPointer point it to?
I know this is probably a prime example of how not to do things in Objective C (especially considering we've got blocks and what not). It's more just curiosity at this point. It almost sounds like I'd need a function pointer pointer, but I'm not sure how that would work, if it's even possible.
This can be done using pointers to function pointers. Perhaps the most readable way to do it is to typedef your function pointer, like this:
typedef void (*FunPtr)(int a, float b);
Then use a pointer of that typedef-ed type to assign in a function, like this:
void foo(int a, float b) {
printf("FOO : %d %f\n", a, b);
}
void bar(int a, float b) {
printf("BAR : %d %f\n", a, b);
}
// This function receives a pointer to function pointer
void assign(int n, FunPtr *ptr) {
if (n == 0) {
*ptr = foo;
} else {
*ptr = bar;
}
}
Here is how you call assign from your code:
int main(void) {
FunPtr f;
assign(0, &f);
f(10, 20.5);
assign(1, &f);
f(10, 20.5);
return 0;
}
Demo.
Note: You are right about blocks in Objective-C greatly reducing the need for direct use of function pointers. However, you can use a similar typedef trick with pointers to blocks.
Related
If I try returning an uninitialized variable, will it guarantee the value is always null/zero?
For example:
struct Rect rect_with_zero_value(){
struct Rect aRect;
return aRect; // Will `aRect` always contain 0 value inside the C struct?
}
void * nullPointer(){
void * pointer;
return pointer; // Will `pointer` always be `Null`?
}
Updated
I find a way to ensure the returning value is always null/zero for any return type except the type void:
#define returnNullValue(ReturnType) \
ReturnType retVal; \
memset(&retVal, 0, sizeof(ReturnType)); \
return retVal
struct Rect rect_with_zero_value(){
returnNullValue(struct Rect); // Return a rect struct which contains 0 value.
}
void * nullPointer(){
returnNullValue(void *);
}
Because I am doing metaprogramming using C macros, I need to find a universal way to ensure the returning value is always null/zero if it is not. And I think this is the solution. Doesn't it?
No. They are not zero.
Only static and global variables have zero value on initialization, for example:
void * nullPointer(){
static void * pointer;
return pointer; // Now pointer is null
}
or
void *pointer; //pointer is null
void * nullPointer(){
return pointer;
}
If I try returning an uninitialized variable, will it guarantee the value is always null/zero?
No, at least not for C.
Moreover: Returning an uninitialised variable implicitly provokes Undefined Behaviour, as returning the value implies reading the (local and uninitialised) variable, which in turn provokes the UB.
Always initialise variables on definition:
struct Rect rect_with_zero_value() {
struct Rect aRect = {0};
return aRect;
}
void * nullPointer() {
void * pointer = NULL;
return pointer;
}
If you do not know to which value to initialise the variables, you propably do not need them at all.
No. If it had a guaranteed value, it would be initialized.
An uninitialized variable contains semi-random junk.
I am trying to create a CLI value class c_Location with overloaded operators, but I think I have an issue with boxing. I have implemented the operator overloading as seen in many manuals, so I'm sure this must be right.
This is my code:
value class c_Location
{
public:
double x, y, z;
c_Location (double i_x, double i_y, double i_z) : x(i_x), y(i_y), z(i_z) {}
c_Location& operator+= (const c_Location& i_locValue)
{
x += i_locValue.x;
y += i_locValue.y;
z += i_locValue.z;
return *this;
}
c_Location operator+ (const c_Location& i_locValue)
{
c_Location locValue(x, y, z);
return locValue += i_locValue;
}
};
int main()
{
array<c_Location,1>^ alocData = gcnew array<c_Location,1>(2);
c_Location locValue, locValue1, locValue2;
locValue = locValue1 + locValue2;
locValue = alocData[0] + alocData[1]; // Error C2679 Binary '+': no operator found which takes a right-hand operand of type 'c_Location'
}
After searching for a longer time, I found that the error comes from the operand being a reference type, as it is an array element of a value type, and the function accepting only value types as it takes an unmanaged reference. I now have 2 possibiblities:
adding a unboxing cast to c_Location and so changing the faulty line in main() to
locValue = alocData[0] + (c_Location)alocData[1];
modifying the operator+ overloading so that it takes the parameter by value instead of by reference:
c_Location operator+ (const c_Location i_locValue)
both options work, but as far as I can see, they both have disadvantages:
opt 1 means that I have to explicitly cast wherever needed.
opt 2 means that the function will create a copy of the parameter on its call and therefore waste performance (not much though).
My questions: Is my failure analysis correct at all or does the failure have another reason?
Is there a better third alternative?
If not: which option, 1 or 2, is the better one? I currently prefer #2.
The rules are rather different from native C++:
the CLI demands that operator overloads are static members of the class
you can use the const keyword in C++/CLI but you get no mileage from it, the CLI does not support enforcing const-ness and there are next to no other .NET languages that support it either.
passing values of a value type ought to be done by value, that's the point of having value types in .NET in the first place. Using a & reference is very troublesome, that's a native pointer at runtime which the garbage collector cannot adjust. You'll get a compile error if you try to use your operator overload on a c_Location that's embedded in a managed class. If you want to avoid value copy semantics then you should declare a ref class instead. The hat^ in your code.
any interop type you create in C++/CLI should be declared public so it is usable from other assemblies and .NET languages. It isn't entirely clear if that's your intention, it is normally the reason you write C++/CLI code.
You could make your value class look like this instead:
public value class c_Location
{
public:
double x, y, z;
c_Location (double i_x, double i_y, double i_z) : x(i_x), y(i_y), z(i_z) {}
static c_Location operator+= (c_Location me, c_Location rhs)
{
me.x += rhs.x;
me.y += rhs.y;
me.z += rhs.z;
return me;
}
static c_Location operator+ (c_Location me, c_Location rhs)
{
return c_Location(me.x + rhs.x, me.y + rhs.y, me.z + rhs.z);
}
};
Untested, ought to be close. You'll now see that your code in main() compiles without trouble.
TL;DR version:
For managed code, use % for a pass by reference parameter, not &
You diagnosis is not completely correct. Boxing has nothing to do with your problem. But reference types do, in a way.
You were really close when you said that "I found that the error comes from the operand being a reference type". Well, the operand is a value type not a reference type. But the error occurs when the operand is stored inside a reference type, because then it's inside the garbage-collected heap (where all instances of reference types are placed). This goes for arrays as well as your own objects which contain a member of value type.
The danger is that when the garbage collector runs, it can move items around on the gc heap. And this breaks native pointers (*) and references (&), because they store the address and expect it to stay the same forever. To handle this problem, C++/CLI provides tracking pointers (^) and tracking references (%) which work together with the garbage collector to do two things:
make sure the enclosing object isn't freed while you're using it
find the new address if the garbage collector moves the enclosing object
For use from C++/CLI, you can make operator+ a non-member, just like normal C++.
value class c_Location
{
public:
double x, y, z;
c_Location (double i_x, double i_y, double i_z) : x(i_x), y(i_y), z(i_z) {}
c_Location% operator+= (const c_Location% i_locValue)
{
x += i_locValue.x;
y += i_locValue.y;
z += i_locValue.z;
return *this;
}
};
c_Location operator+ (c_Location left, const c_Location% right)
{
return left += right;
}
The drawback is that C# won't use non-members, for compatibility with C#, write it like a non-member operator (with two explicit operands) but make it a public static member.
value class c_Location
{
public:
double x, y, z;
c_Location (double i_x, double i_y, double i_z) : x(i_x), y(i_y), z(i_z) {}
c_Location% operator+= (const c_Location% i_locValue)
{
x += i_locValue.x;
y += i_locValue.y;
z += i_locValue.z;
return *this;
}
static c_Location operator+ (c_Location left, const c_Location% right)
{
return left += right;
}
};
There's no reason to worry about this for operator+= since C# doesn't recognize that anyway, it will use operator+ and assign the result back to the original object.
For primitive types like double or int, you may find that you need to use % also, but only if you need a reference to an instance of that primitive type is stored inside a managed object:
double d;
array<double>^ a = gcnew darray<double>(5);
double& native_ref = d; // ok, d is stored on stack and cannot move
double& native_ref2 = a[0]; // error, a[0] is in the managed heap, you MUST coordinate with the garbage collector
double% tracking_ref = d; // ok, tracking references with with variables that don't move, too
double% tracking_ref2 = a[0]; // ok, now you and the garbage collector are working together
I have a method that returns an integer and I now also want to return a small struct or class. If I was using C++ I would pass a reference to the struct in as a parameter. In iOS using ARC, I think the equivalent is to use a pointer to a pointer that has the __autoreleasing attribute which I find a bit cumbersome.
I could return an array containing the two values but then think I would be alloc'ing more than necessary and I could be using this a lot (100,000 calls).
Even with ARC, you can just pass in a struct by reference or an object pointer...
Pass the struct by ref just like you would in C++, e.g. &aStruct
-(int)getStuffOut:(SomeStruct *)aStruct {
if(!aStruct) {
return 0;
}
aStruct->myInt = 12345;
aStruct->myFloat = 12.345f;
return 1;
}
Or:
-(int)getStuffOut:(SomeClass *)anObject {
if(!anObject) {
return 0;
}
anObject.myIntProperty = 12345;
anObject.myFloatProperty = 12.345f;
return 1;
}
If you're using ARC you dont have to worry about memory management if you're using plain Objective-C.
Custom objects are passed by reference, so you can pass your OBJ-C object to your method and fill your stuff in.
Or you can return a Struct that holds the two values
+(struct YourStruct)someMethod:(NSString *)someParam;
+(YourStruct)someMethod:(NSString)someParam {
//some method code
YourStruct st;
//Do something here with the struct
return st;
}
I've got an Interop wrapper to some unmanaged DLL calls that return details through out paremeters. The functions appear like this:
_myWrapper->My_Method( ... out UInt32 value ... );
So assuming the method is declared like this:
void My_Method(out UInt32 value);
How do I then call this method from within my C++/CLI code? I know how to call reference methods such as this easy enough:
void Another_Method(ref UInt32 value);
UInt32 _value;
_myWrapper->Another_Method(%_value);
I'm doing a little reading and I am reading it can't be done? I don't believe it... Likely this isn't impossible to overcome or workaround, but you've got to be kidding me? Is that really true?
Thank you...
In C++, there's no special call syntax for calling a function with a reference parameter, you just write the call like it was pass-by-value. Of course, you need to supply an lvalue to be overwritten, the rvalue (temporary) result of an arithmetic expression can't be used.
BTW, your code for calling a ref function is wrong too, that might be the source of your troubles.
Example:
C# definition:
void MySharpRef(ref int i) { i = 4; }
void MySharpOut(out int i) { i = 5; }
C++/CLI definition:
void MyPlusRef(System::Int32% i) { i = 14; }
void MyPlusOut([System::Runtime::InteropServices::OutAttribute] System::Int32% i) { i = 15; }
C# call:
int j;
o.MyPlusOut(out j);
o.MyPlusRef(ref j);
C++/CLI call:
System::Int32 k;
p->MySharpOut(k);
p->MySharpRef(k);
Not sure what I'm doing wrong here. I have a struct that is used heavily through my program.
typedef struct _MyStruct {
// ... handful of non-trivial fields ...
} MyStruct;
I expect (read, intend) for lots of parts of the program to return one of these structs, but many of them should be able to return a "null" struct, which is a singleton/global. The exact use case is for the implementing function to say "I can't find what you asked me to return".
I assumed this would be a simple case of defining a variable in a header file, and initializing it in the .c file.
// MyStruct.h
// ... Snip ...
MyStruct NotFoundStruct;
-
// MyStruct.c
NotFoundStruct.x = 0;
NotFoundStruct.y = 0;
// etc etc
But the compiler complains that the initialization is not constant.
Since I don't care about what this global actually references in memory, I only care that everything uses the same global, I tried just removing the initialization and simply leaving the definition in the header.
But when I do this:
MyStruct thing = give_me_a_struct(some_input);
if (thing == NotFoundStruct) {
// ... do something special
}
Th compiler complains that the operands to the binary operator "==" (or "!=") are invalid.
How does one define such as globally re-usable (always the same memory address) struct?
This doesn't directly answer your question, but it won't fit in a comment...
If you have a function that may need to return something or return nothing, there are several options that are better than returning a "null struct" or "sentinel struct," especially since structs are not equality comparable in C.
One option is to return a pointer, so that you can actually return NULL to indicate that you are really returning nothing; this has the disadvantage of having significant memory management implications, namely who owns the pointer? and do you have to create an object on the heap that doesn't already exist on the heap to do this?
A better option is to take a pointer to a struct as an "out" parameter, use that pointer to store the actual result, then return an int status code indicating success or failure (or a bool if you have a C99 compiler). This would look something like:
int give_me_a_struct(MyStruct*);
MyStruct result;
if (give_me_a_struct(&result)) {
// yay! we got a result!
}
else {
// boo! we didn't get a result!
}
If give_me_a_struct returns zero, it indicates that it did not find the result and the result object was not populated. If it returns nonzero, it indicates that it did find the result and the result object was populated.
C doesn't allow global non-const assignments. So you must do this in a function:
void init() {
NotFoundStruct.x = 0;
NotFoundStruct.y = 0;
}
As for the comparison, C doesn't know how to apply a == operator to a struct. You can overload (redefine) the operator in C++, but not in C.
So to see if a return value is empty, your options are to
Have each function return a boolean value to indicate found or not, and return the struct's values via pointers through the argument list. (eg. bool found = give_me_a_struct(some_input, &thing);)
Return a pointer to a struct, which can be NULL if nothing exists. (eg. MyStruct* thing = give_me_a_struct(some_input);)
Add an additional field to the struct that indicates whether the object is valid.
The third option is the most generic for other cases, but requires more data to be stored. The best bet for your specific question is the first option.
// MyStruct.h
typedef struct _MyStruct {
// fields
} MyStruct;
extern MyStruct NotFoundStruct;
// MyStruct.c
#include "my_struct.h"
MyStruct NotFoundStruct = {0};
But since you can't use the == operator, you will have to find another way to distinguish it. One (not ideal) way is to have a bool flag reserved to indicate validity. That way, only that must be checked to determine if it's a valid instance.
But I think you should consider James's proposed solution instead
In the header:
// Structure definition then
extern MyStruct myStruct;
In the .c that contains global data
struct MyStruct myStruct
{
initialize field 1,
initialize field 2,
// etc...
};