I have a C struct.
typedef struct Vector2 {
float x;
float y;
} Vector2;
When used in Swift its members become immutable, so I've written a Swift counterpart that conforms to Equatable, supports arithmetic operators, etc.
struct Vector {
var x: Float
var y: Float
}
In order to use the Swift type as a substitute argument in C methods, I need to bridge it somehow.
I realize I could have a computed property on my Swift type .vector2: Vector2 {}, but I'd prefer to use the as keyword.
Is this possible?
swiftVector as Vector2
Related
I'm writing in C and would like to have some implementation of type variables. In Haskell for example I could write something like:
data Matrix a = Matrix [a] Int Int
which would let me define matrices with entries of any type 'a'. In C, I've written for each type some structure:
struct zMatrix {
int dim_row;
int dim_col;
int *coords;
};
struct rMatrix {
int dim_row;
int dim_col;
float *coords;
};
...
Is there some way to have a generic matrix structure and some function to create a matrix which would specify the type of the coords field? Something like:
struct matrix {
int dim_row;
int dim_col;
(typevar type) *coords;
};
struct matrix matrixCreate(typevar type, int n, int m){...};
struct matrix M = matrixCreate(int, 3, 3);
struct matric M = matrixCreate(float, 3, 3);
...
You can do it. As #EOF mentioned, you can use a union type for the portion of the structure that is different for different data types. You'll probably want to store something representing the type in the structure as well. You can't pass a type name to a function as in your example, but you can define an enum that represents the various types. You would then use switch statements to implement any type-specific code. An alternative to using switch statements is to use a data structure which describes a type (this would contain function pointers and possibly other information). You would declare an instance of that data structure for each type and your type-specific code would use information in the appropriate type's data structure to do what it needs to do. The type data structures could be in an array which you would index with the type enum value, or you could use a pointer to the type data structure to represent the type.
If C++ is an option, that would make this a lot easier.
Some simple Rust code:
struct Point {
x: f64,
y: f64,
}
fn main() {
let p: &Point = &(Point { x: 0.3, y: 0.4 });
// println!("{:?}" , p->x); // no sugar here for Rust
println!("{:?}", (*p).x);
println!("{:?}", p.x); // sugar?
// no leak right? thanks Rust
}
And some similar C code
#include <stdio.h>
#include <stdlib.h>
typedef struct Point Point;
struct Point {
float x;
float y;
};
int main() {
Point __tmp = { 0.3, 0.4 };
Point* p = &__tmp;
printf("%f\n", p->x); // C sugar for below
printf("%f\n", (*p).x);
// below doesn't work because p is a pointer to a point
//printf("%f", p.x); // error: request for member 'x' in something not a structure or union
// memory leak at this point right?
return 0;
}
It seems that p is a pointer to a Point in both pieces of code.
I want to make sure that Rust implementing p.x is (or can be thought of as) syntactic sugar and that I don't have a fundamental misunderstanding of what is going on.
Is this what they mean by aliasing? Is p in Rust more like an alias?
p.x is indeed sugar in a certain sense. Rust automatically dereferences any type that implements the trait Deref or DerefMut(depending on whether the context requires a mutable or immutable reference), when doing method/attribute look-up.
In your example, the reference &Point implements Deref<Target=Point>, so your p.x expression is expanded to (*p).x. Note that this only works, as long as the pointer type does not have an attribute/method named x of its own (which is not the case for a simple refererence).
There is another question on SO that goes on about the detailed rules for auto-dereferencing.
I'm in the process of translating some C code to Fortran & I have run across some instances which have me scratching my head as to how to properly convert the C to Fortran.
Example #1-
typedef struct fileheadtype
{
char version[128];
char notes[256];
} FileHeadType;
typedef struct linetype
{
LineInfo info;
float latlon[50];
} LineType;
typedef struct vg_dbstruct
{
VG_HdrStruct hdr;
union
{
FileHeadType fhed;
LineType lin;
} elem;
} VG_DBStruct;
I understand the 'fileheadtype' and 'linetype' structures but I don't understand what the vg_dbstruct is doing, how it relates to the other two structures and how to properly translate to Fortran.
Example #2-
typedef struct breakpt_t { /* break point structure */
float lat;
float lon;
char breakPtName[ 100 ];
} Breakpt_T;
enum tca_adv_t {
WATCH = 0,
WARNING = 1
};
typedef struct tcaww_t {
enum tca_adv_t advisoryType;
int numBreakPts;
struct breakpt_t *breakPnt;
} TcaWw_T;
Here, i don't understand what the enumeration operation is doing in the tcaww_t struct nor the "breakpt_t" struct is doing and...how to translate to Fortran.
Any help is greatly appreciated
Jeff
Typedef is something Fortran doesn't have. It enables you to call some type or structure by a different name. You can even do
typedef int myint;
and use myint as name of a type
myint i;
With the example one you can then use
FileHeadType fh;
instead of
struct fileheadtype fh;
which will translate to type(fileheadtype).
In Fortran you always need to use the original type, whether it is integer or type(typename).
The enumerations exist in Fortran for C interoperability, but if you don't want to call C, but you just do a translation in Fortran spirit, you can just use integers:
integer, parameter :: WATCH = 0, WARNING = 1
Unions are not part of Fortran, you must study the intention of the code and either use two separate components, or use transfer() or equivalence.
I have 2 matrix structs means equal data but have different form like these:
// Matrix type 1.
typedef float Scalar;
typedef struct { Scalar e[4]; } Vector;
typedef struct { Vector e[4]; } Matrix;
// Matrix type 2 (you may know this if you're iPhone developer)
// Defines CGFloat as float for simple description.
typedef float CGFloat;
struct CATransform3D
{
CGFloat m11, m12, m13, m14;
CGFloat m21, m22, m23, m24;
CGFloat m31, m32, m33, m34;
CGFloat m41, m42, m43, m44;
};
typedef struct CATransform3D CATransform3D;
Their memory sizes are equal. So I believe there is a way to convert these types without any pointer operations or copy like this:
// Implemented in external lib.
CATransform3D CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz);
Matrix m = (Matrix)CATransform3DMakeScale ( 1, 2, 3 );
Is this possible? Currently compiler prints an "error: conversion to non-scalar type requested" message.
Probably the best solution would be to combine your two structs into a union. If you want to interpret the same data in two different ways then it's the obvious choice. The alternative is to use pointer casts, but that's ugly, breaks aliasing rules, and can hide errors that might otherwise be reported by the compiler.
typedef float Scalar;
typedef struct { Scalar e[4]; } Vector;
typedef struct { Vector e[4]; } Matrix;
struct CATransform3D
{
CGFloat m11, m12, m13, m14;
CGFloat m21, m22, m23, m24;
CGFloat m31, m32, m33, m34;
CGFloat m41, m42, m43, m44;
};
typedef struct CATransform3D CATransform3D;
typedef union
{
CATransform3D t;
Matrix m;
} UMatrix;
CATransform3D CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz);
UMatrix um;
um.t = CATransform3DMakeScale ( 1, 2, 3 );
//
// now you can just use um.m when you need to refer to the Matrix type...
//
Well, you could just declare CATransform3DMakeScale like this:
Matrix CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz);
C doesn't type-check to make sure your deceleration matches the original library. If the memory layout is the same, it will work. However, it's bad coding practice and you should include a lengthy comment justifying your actions. ;-)
Otherwise, there's no way around it: you have to use pointers or copy the data. This would work:
CATransform3D m3d = CATransform3DMakeScale ( 1, 2, 3 );
Matrix m;
memcpy(&m, &m3d, sizeof m);
As you've discovered, you can't cast the structure directly. You also can't do this:
Matrix m = *(Matrix*) &CATransform3DMakeScale ( 1, 2, 3 );
because C only allows you to use the & operator on an l-value.
I'm trying to learn C and I've come across something weird:
struct
{
int i;
double j;
} x, y;
struct
{
int i;
double j;
} z;
Here, you can see I created two structs that are identical in their elements.
Why is it that when I try to assign x = z it will generate a compile error but x = y does not? They have the same contents, so why can't I assign them back and forth with each other, regardless?
Is there any way I can make this so I can assign x = z? Or do they simply have to be the same struct.
Can any C gurus point me in the right direction?
They have the same content, but not the same type. If they are intended to be of the same type, simply typedef x z;. If they aren't the same thing, but just happen to contain the same fields, it's better to create a separate function that will assign the fields properly.
My usual style for declaring structs in C includes the typedef, so I forgot to mention it (sorry!). Here's the syntax:
typedef struct
{
int foo;
double bar;
} x;
/* Further down, if needed */
typedef x z;
Making identically structured types the same is called "duck typing". This is done in some languages, but not in C.
The compiler does not calculate "type equivalence" between structs that may have the same structure, so as far as it is concerned, the second struct has nothing to do with the first one.
It can do x and y because they are declared at the same time.
Why are you redeclaring the struct ? You should probably typedef the struct once (e.g., in an H file) to make it an actual type, and then declare instances.
Here's a good tutorial on typedefs for structs.
struct mystruct
{
int i;
double j;
};
struct mystruct x, y;
struct mystruct z;
If you intend to copy data between them, you must declare them with the same identity. You have two declarations, it doesn't matter they are equal for the compiler, they are two different structures, and the compiler is not supposed to detect their similarity.
C differentiates structs based on name, and if they're anonymous, then different structure definitions are different.
Anyhow, classic C doesn't allow x = z when x and z are structs -- is that an ANSI or a C99 addition? Anyhow, you should instead use
#include <string.h>
memcpy(&x, &z, sizeof(x));