Passing Incompatible Structs Between C and XC

Technical questions regarding the XTC tools and programming with XMOS.
Post Reply
gcore
Member
Posts: 11
Joined: Thu Oct 06, 2016 4:58 am

Passing Incompatible Structs Between C and XC

Post by gcore »

I would like to be able to pass a struct by reference from XC, through some C function calls, back to an XC function, where it would be usable as if it had never been passed via C. The particular struct I would like to pass is shown here.

Code: Select all

#include <xccompat.h>
#ifndef __XC__
#define movable
#endif

typedef struct
{
    unsigned a;
    unsigned b;
    chanend *movable c;
} MyStruct;
In XC land, this struct can be passed by reference to any XC function I want, and I can operate on chanend *movable c as one would expect to be able to. The problem enters when I try to pass a MyStruct reference to a C function. Usually xccompat.h helps with this, where I can use REFERENCE_PARAM(MyStruct, myStructRef) in the function headers to convert the reference to a pointer for the C function calls. In this instance, I also need to remove the "movable" keyword for the C side of the build by doing "#ifndef (__XC__) #define movable ". This removes the movable keyword when built for C, but in the process changes the definition of MyStruct for C versus XC, causing a compilation error.

c_functions.c: Error: Type of symbol first_c_function has mismatch with previous definition:
c_functions.c: Error: found: void first_c_function(struct *)
../main.xc: Error: previous: void first_c_function(struct &)
../xc_functions.xc: Error: Type of symbol second_xc_function has mismatch with previous definition:
../xc_functions.xc: Error: found: void second_xc_function(struct &)
c_functions.c: Error: previous: void second_xc_function(struct *)

Please see my attached project showing the compilation errors. In the project, the issue is removed by removing "chanend *movable c;" from MyStruct, but so is the functionality I'm after.

The "Calling between C/C++ and XC" document shows examples of how to perform similar operations, but does not provide much depth.
https://www.xmos.com/download/private/C ... 65A%29.pdf

Is there a way to do what I'm after?
Attachments
tester.zip
(3.55 KiB) Downloaded 204 times
tester.zip
(3.55 KiB) Downloaded 204 times


robertxmos
XCore Addict
Posts: 169
Joined: Fri Oct 23, 2015 10:23 am

Post by robertxmos »

Hi gcore

As with all 'casting' it is important to know what you are forcing the compiler to do.
In this case the type '*movable' is a smart-pointer with a size of 12 bytes (information about the underlying object is held).
The XC pointer type '*unsafe' is a raw pointer of size 4 bytes - the same as a C raw pointer.
Thus, under XC and C the structure is of a different size.
I am not sure what your intentions are, but a quick hack would be:

Code: Select all

typedef struct {
    unsigned a;
    unsigned b;
#ifndef __XC__
    chanend *movable c;
#else
    unsigned opaque_c[3];
#endif
} MyStruct;
or possibly:

Code: Select all

typedef struct {
    unsigned a;
    unsigned b;
    chanend *unsafe c; // 4 byte raw pointer same in XC & C
} MyStruct;
By the way, when you use a plain '*' in XC, it is always an implicit '*alias' or '*restricted' - depending upon the situation.
when it can't know anything about aliasing because it is in global scope it is read as '*restricted' - viz not allowed to alias with another pointer.
when it is in local scope (function param or auto variable) it is '*alias' - compiler as full view of usage and will check if aliasing is an issue.
In both cases the compiler can optimise with full knowledge of potential aliasing issues
Post Reply