Question

I have this code:

unsigned short (*pixel_array)[SCREEN_HEIGHT] = get_ok_zone(mouse_mask); 
unsigned short (*pixel_border)[2] = get_ok_zone_border(pixel_array); 

that gets me access to both of these data arrays.

I need to somehow pass both of these arrays as ONE argument to a function.

Not only can I not figure out how to pass them, I can't figure out how to access the arrays individually once I get them into the function.

I have been trying all day to understand this, and it just seems to be escaping me.

Can someone explain to me what exactly I need to do to pass both of these arrays through one argument (probably in an array of pointers?) to a function, and how to access them on the inside of the function?

edit: I'm passing the argument (the only argument I am allowed to pass) to a Quartz Event Tap callback.

edit 2: @Kevin

I created the struct:

struct array_stack {
    unsigned short (*pixel_array)[SCREEN_HEIGHT]; 
    unsigned short (*pixel_border)[2]; 
};

Then, in my int main() I have:

struct array_stack as = {get_ok_zone(mouse_mask), get_ok_zone_border(get_ok_zone(mouse_mask))};



CFRunLoopSourceRef runLoopSource;
CGEventMask event_mask;
event_mask = CGEventMaskBit(kCGEventMouseMoved) | CGEventMaskBit(kCGEventLeftMouseDragged) | CGEventMaskBit(kCGEventRightMouseDragged) | CGEventMaskBit(kCGEventOtherMouseDragged);

CGSetLocalEventsSuppressionInterval(0);

CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 0, event_mask, mouse_filter, as);

(I pass the as as the very last argument for the CGEventTapCreate() at the bottom of the code block);

I get an error passing struct array_stack to a parameter of incompatible type 'void' , the error points me to this:

CG_EXTERN CFMachPortRef CGEventTapCreate(CGEventTapLocation tap,
CGEventTapPlacement place, CGEventTapOptions options,
CGEventMask eventsOfInterest, CGEventTapCallBack callback,
void *userInfo) CG_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_NA);

void *userInfo is the parameter that receives my argument, which eventually gets passed through to the callback function.

Was it helpful?

Solution

Expanding on Kevin's answer, the way you do this is with a pointer to a structure. You do have to be careful about object lifetimes, however: the structure has to continue to stay valid for as long as the data may be accessed.

If you can guarantee the lifetime of when the data may be accessed, you can use a stack variable or a global variable:

typedef struct pixel_data
{
    unsigned short (*pixel_array)[SCREEN_HEIGHT];
    unsigned short (*pixel_border)[2];
} pixel_data;

...

pixel_data data = {get_ok_zone(mouse_mask), get_ok_zone_border(pixel_array)};
CGEventTapCreate(..., &mouse_filter, &data);
// 'data' must remain alive for as long as mouse_filter might get called

...

CGEventRef mouse_filter(..., void *refcon)
{
    pixel_data *data = refcon;  // implicit cast
    // do stuff with data->pixel_array and data->pixel_border
}

If you only have one callback alive at any given time, you can use a global object (and in that case, you actually don't even need to pass the data via the void* parameter—you can just access the global data from the callback).

More likely, if you have multiple callbacks in flight with potentially different data, the only safe thing to do is to malloc each callback's data when created and free it when done:

pixel_data *data = malloc(sizeof(pixel_data));
data->pixel_array = ...;
data->pixel_border = ...;
CGEventTapCreate(..., &mouse_filter, data);
...
// When the event is deleted/done/whatever:
free(data);  // The callback mouse_filter should never be called after this
             // with this data

OTHER TIPS

Wrap them in a struct:

struct wrapper {
    unsigned short (*arr)[SCREEN_HEIGHT];
    unsigned short (*border)[2];
}

This is a common trick, especially for callbacks. You can use it to pass anything through a void * by passing a pointer to the struct where you have stored everything.

This is how you do it.

Code:

#include <stdio.h>
#define SCREEN_HEIGHT 2

struct container {
unsigned short (*pixel_array)[SCREEN_HEIGHT]; 
unsigned short (*pixel_border)[2]; 
};

void function(struct container );

int main (){
struct container container1;

container1.pixel_array = (int *) malloc (2*sizeof(int *));
container1.pixel_border = (int *) malloc (2*sizeof(int *));
(*container1.pixel_array)[0] = 88;
(*container1.pixel_array)[1] = 99;
(*container1.pixel_border)[0] = 77;
(*container1.pixel_border)[1] = 66;

function(container1);

return 0;}

void function(struct container x) {
printf("container1.pixel_array[0] = %d\n",(*x.pixel_array)[0]);
printf("container1.pixel_array[1] = %d\n",(*x.pixel_array)[1]);
printf("container1.pixel_border[0] = %d\n",(*x.pixel_border)[0]);
printf("container1.pixel_border[1] = %d\n",(*x.pixel_border)[1]);
}

Output:

container1.pixel_array[0] = 88
container1.pixel_array[1] = 99
container1.pixel_border[0] = 77
container1.pixel_border[1] = 66

However, I got 2 warnings, can anyone help to point out how to correct the warnings?

warning:

struct_2array.c:19: warning: assignment from incompatible pointer type
struct_2array.c:20: warning: assignment from incompatible pointer type

container1.pixel_array = (int *) malloc (2*sizeof(int *));
container1.pixel_border = (int *) malloc (2*sizeof(int *));

Update: To suit the OP's function that takes void * as an argument, I changed the code a little bit, however, I'm still getting warning for the malloc line:

#include <stdio.h>
#define SCREEN_HEIGHT 2

struct container {
unsigned short (*pixel_array)[SCREEN_HEIGHT]; 
unsigned short (*pixel_border)[2]; 
};

void function(void *);

int main (){
struct container container1;

container1.pixel_array = malloc (2*sizeof(int *));
container1.pixel_border =  malloc (2*sizeof(int *));
(*container1.pixel_array)[0] = 88;
(*container1.pixel_array)[1] = 99;
(*container1.pixel_border)[0] = 77;
(*container1.pixel_border)[1] = 66;

function(&container1);

return 0;}

void function(void *x) {
struct container container2 = *(struct container *)x;
printf("container1.pixel_array[0] = %d\n",(*container2.pixel_array)[0]);
printf("container1.pixel_array[1] = %d\n",(*container2.pixel_array)[1]);
printf("container1.pixel_border[0] = %d\n",(*container2.pixel_border)[0]);
printf("container1.pixel_border[1] = %d\n",(*container2.pixel_border)[1]);
}

Use a struct, that's probably easiest.

Or union void* if you wanted to pass either.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top