How to use D structures from C code? - c

Could anyone explain me how to use D structures from C code? If I am trying to use it I receive such an error:
error: storage size of 'myStruct' isn't known
struct str_struct myStruct;
This is a structure:
extern(C) {
struct str_struct {
string str;
};
}
I use it in C like this : struct str_struct myStruct;

You have to duplicate the struct definition with all members in both languages (unless you want to refer to it only by pointer). C can't see a field list written in D.
D:
struct Foo {
int length;
int* data;
}
C:
typedef struct Foo {
int length;
int* data;
};
The tricky thing is to get long right. long in D is always 64 bits, so in C, that would be long long. Most other basic types translate pretty easily though: short=>short, int to int, char to char, pointers work the same way, etc.

Related

C access enum from struct

My problem is that car_name_str could not be resolved. Why is it not callable and I want to keep the code structure?
I want to keep the structure as struct with union and enum (different datatypes).
Template: How can mixed data types (int, float, char, etc) be stored in an array?
//car_union.h
typedef struct {
enum { number_of_seats_int, car_cost_float, car_name_str } type;
union {
int number_of_seats;
float car_cost;
char* car_name;
} value;
}Car_data_ex[30][3];
extern Car_data_ex *Car_data[30][3];
//fill_car.c
#include "car_union.h"
Car_data_ex *Car_data[30][3];
Car_data[0][0]->type = car_name_str; //-> because pointer but doesnt work
Car_data[0][0]->value->car_name= "land rover";
Car_data[0][1]->type = car_cost_float; //doesnt work
Car_data[0][1]->value->car_cost= 45000;
Just remove the [30][3] from the type def, like this
#include <stdio.h>
//car_union.h
typedef struct {
enum { number_of_seats_int, car_cost_float, car_name_str } type;
union {
int number_of_seats;
float car_cost;
char* car_name;
} value;
}Car_data_ex;
extern Car_data_ex *Car_data[30][3];
int main() {
Car_data_ex *Car_data[30][3];
Car_data[0][0]->type = car_name_str; //-> because pointer but doesnt work
Car_data[0][0]->value.car_name= "land rover";
Car_data[0][1]->type = car_cost_float; //doesnt work
Car_data[0][1]->value.car_cost= 45000;
}
Regardless of what's in your struct, when you do
typedef struct Car_dataStructTag{
//...
}Car_data_ex[30][3];
(I've tagged the struct so it can be referred to by struct Car_dataStructTag),
then Car_data_ex is a type alias resolving to struct Car_dataStructTag [30][3]
which means
extern Car_data_ex *Car_data[30][3];
is fully equivalent to
extern struct Car_dataStructTag (*Car_data[30][3])[30][3];
which means Car_data[x][y] is a pointer to a two-dimensional array of struct Car_dataStructTag,
which is definitely not something you can apply -> to.
Try:
typedef struct Car_dataStructTag{
//...
}Car_data_ex[30][3];
extern Car_data_ex *Car_data[30][3];
extern struct Car_dataStructTag (*Car_data[30][3])[30][3];
in a compiler -- it gets accepted, confirming the declaration equivalence.
Running into situations such as this one is why it's generally considered ill-advisable to typedef arrays or pointers.
You have over complexified everything.
A typedef is just to give an alias to a (complex) type. Here the type is a struct containing an enum and an union. So it should be:
typedef struct {
enum { number_of_seats_int, car_cost_float, car_name_str } type;
union {
int number_of_seats;
float car_cost;
char* car_name;
} value;
}Car_data_ex;
Next, using an array of pointers can make sense, but provided each pointer in the array does point to a true object. Here you only want a plain (2D) array:
Car_data_ex Car_data[30][3];
Once this has been done, you can write with no error or warning:
Car_data[0][0].type = car_name_str;
Car_data[0][0].value.car_name= "land rover";
Car_data[0][1].type = car_cost_float;
Car_data[0][1].value.car_cost= 45000;
And you should avoid extern Car_data_ex Car_data[30][3];. It declares a global array, that will have to be defined in one single compilation unit (.c file). Here again, it can make sense, but IMHO it is a rather advanced feature that can be hard to correctly use. And nothing in the shown code lets think that is is required...

Structure pointer pointing to different structure instance

struct first_struct
{
int a;
int b;
};
struct second_struct
{
char d;
int e;
};
struct second_struct second_ins = {'a',10};
struct first_struct first_ins = {20,12};
int main()
{
struct second_struct *pointer = &first_ins;
printf("%d\n",pointer->d);
return 0;
}
And I get an output of 20. Basically, I was trying to see that if I declare a structure pointer, and try to point this to an instance of another structure, what result do I get. Besides a warning from compiler for an incompatible pointer type, it builds and runs fine.
I was trying to understand how this operation was interpreted by compiler. Shouldnt this be undefined, or may be it is and I am just getting lucky with the result.
It's likely that both structs have the same element-wise alignment: sizeof(first_struct) == sizeof(second_struct) and: int e starts at the same offset in the struct as: int b
In other words, char d is effectively stored as an int in terms of layout. It's simply a lucky coincidence on your platform, and will not work portably.

Translating C Structures to Fortran Equivalents

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.

Kind of polymorphism in C

I'm writing a C program in which I define two types:
typedef struct {
uint8_t array[32];
/* struct A's members */
...
} A;
typedef struct {
uint8_t array[32];
/* struct B's members, different from A's */
...
} B;
Now I would like to build a data structure which is capable of managing both types without having to write one for type A and one for type B, assuming that both have a uint8_t [32] as their first member.
I read how to implement a sort of polymorphism in C here and I also read here that the order of struct members is guaranteed to be kept by the compiler as written by the programmer.
I came up with the following idea, what if I define the following structure:
typedef struct {
uint8_t array[32];
} Element;
and define a data structure which only deals with data that have type Element? Would it be safe to do something like:
void f(Element * e){
int i;
for(i = 0; i < 32; i++) do_something(e->array[i]);
}
...
A a;
B b;
...
f(((Element *)&a));
...
f(((Element *)&b));
At a first glance it looks unclean, but I was wondering whether there are any guarantees that it will not break?
If array is always the first in your struct, you can simply access it by casting pointers. There is no need for a struct Element. You data structure can store void pointers.
typedef struct {
char array[32];
} A;
typedef struct {
void* elements;
size_t elementSize;
size_t num;
} Vector;
char* getArrayPtr(Vector* v, int i) {
return (char*)(v->elements) + v->elementSize*i;
}
int main()
{
A* pa = malloc(10*sizeof(A));
pa[3].array[0] = 's';
Vector v;
v.elements = pa;
v.num = 10;
v.elementSize = sizeof(A);
printf("%s\n", getArrayPtr(&v, 3));
}
but why not have a function that works with the array directly
void f(uint8_t array[32]){
int i;
for(i = 0; i < 32; i++) do_something(array[i]);
}
and call it like this
f(a.array)
f(b.array)
polymorphism makes sense when you want to kepp
a and b in a container of some sorts
and you want to iterate over them but you dont want to care that they are different types.
This should work fine if you, you know, don't make any mistakes. A pointer to the A struct can be cast to a pointer to the element struct, and so long as they have a common prefix, access to the common members will work just fine.
A pointer to the A struct, which is then cast to a pointer to the element struct can also be cast back to a pointer to the A struct without any problems. If element struct was not originally an A struct, then casting the pointer back to A will be undefined behavior. And this you will need to manage manually.
One gotcha (that I've run into) is, gcc will also allow you to cast the struct back and forth (not just pointer to struct) and this is not supported by the C standard. It will appear to work fine until your (my) friend tries to port the code to a different compiler (suncc) at which point it will break. Or rather, it won't even compile.

Allocating memory and filling the structure elements of a structure

I have defined the structure in a separate header file and I have included that header file in my main file.
The header file consists of a structure like this:
typedef struct
{
char name[32];
unsigned int a;
unsigned int b;
NUMBER_ONE variable1;
NUMBER_TWO variable2;
}NUMBER_THREE,*PNUMBER_THREE;
typedef struct
{
unsigned int variable3;
char variable4[8];
}NUMBER_ONE,*PNUMBER_ONE;
typedef struct
{
unsigned int variable5;
char variable6[8];
}NUMBER_TWO,*PNUMBER_TWO;
Now in my main file I have to allocate memory for this structure and I need to fill this structure with some values, so anybody please tell me how to do this. I need to send this through socket client to the socket server.
If you have written it in that order you present it, then the code should not even compile since the first typedef has no clue on what NUMBER_ONE or NUMBER_TWO types are.
To allocate it should just be to define a variable of given type.
int main()
{
NUMBER_TWO number_two_var;
number_two_var.variable5 = 10;
}
I would also recommend using a postfix for each typdef, for example NUMBER_TWO_T.
Edit: Postfix being _T
In C a struct is initialized by an initializer
NUMBER_TWO a2 = { .variable5 = 7, .variable6 = { 'a', }, };
the form I am giving here are so-called designated initializers that came starting with C99. Oldish C had only the equivalent
NUMBER_TWO a2 = { 7, { 'a' } };
where you have to specify the values in declaration order.
For both forms, fields that are omitted from the initializer are initialized with 0.

Resources