Given two structure in c:
typedef struct _X_
{
int virtual_a;
int virtual_b;
void *virstual_c;
int a;
int b;
void *c;
/* More fields to follow */
}X;
typedef struct _Y_
{
int a;
int b;
void *c;
/* Same fields as in X structure */
}Y;
Q : Is it safe to say that ?
void foo_low( Y *y )
{
y->a = 1;
y->b = 2;
}
void foo( X *x )
{
Y *y = (Y *)(&(x->a) )
foo_low( y );
}
Is it standard C ? will it work on all compilers ? Is there any problem with padding ?
No, your function foo won't work, because a is in the wrong place.
Your example is clearly made up and tha's going to reduce the relevance of my answer to the problem you are really trying to solve, but this definition does something like I believe you are asking for:
struct header {
int a;
int b;
void *c;
};
struct shared_fields {
int a;
int b;
void *c;
/* More fields to follow */
};
typedef struct
{
struct header virtuals;
struct shared_fields shared;
} X;
typedef struct
{
struct shared_fields shared;
} Y;
void foo_low(struct shared *ys)
{
ys->a = 1;
ys->b = 2;
}
void foo(X *x)
{
foo_low(&x->shared);
}
However, this does not perform a cast, since one is not needed. If you really intended to set data via one struct and access it via another, this is not allowed in standard C (though there might be an exception for same-struct-with-different labels as described by Hubert).
I suspect that a better solution to the problem you asked about is the use of union which can often be used to do what you may have in mind. But strictly speaking, if you have an object u of union type and you set u.a, accessing the value of u.b before setting u.b has undefined behaviour. Though commonly people do not worry about that.
That should work. But since you need to access the same fields in two distinct ways (y->a and x->a are different), I would use union:
typedef struct _Y_
{
int a;
int b;
void *c;
/* Same fields as in X structure */
}Y;
typedef struct _X_
{
int virtual_a;
int virtual_b;
void *virstual_c;
Y y_fields;
}X;
typedef union {
X x;
Y y;
} Z;
Now x.virtual_a and y.a are in the same memory address.
And you can rewrite your code as follows:
void foo_low( Z *z )
{
z->y.a = 1;
z->y.b = 2;
}
void foo( Z *z )
{
Z *w = z;
w->y = z->x.y_fields;
foo_low( w );
}
The only clumsy part is adding Y inside X.
if both structs have identically structure it is ok. Names of fields inside the struts need not to be the same, but their types must be the same. Each subfield in X must match to a subfield in Y in its type and position. Names of fields can be different.
Related
I have a c struct that has a const variable.
typedef struct {
u32 status;
const u32 dir_search_idx;} FS_OBJ;
What I would like to do is init the const variable in a function once I have created the struct object. I guess I want to do something similar to what a constructor would do in c++. Is it possible to do something similar in c? Thanks
This should work perfectly fine if you are using C99 or newer and want to initialize the const variable when creating the struct:
FS_OBJ obj = { .status = /* something */, .dir_seach_idx = /* something */ };
You can't modify the const variable after creating the struct. Then you would have to remove the const keyword as mentioned by user3386109 in the comments.
I think const is not the right tool for what you are looking for. You can put data (structs) and behavior (functions) in a *.c file and provide public functions in the corresponding header file. This way you can mimic the equivalent c++ code that you want and hide the data and of course, you can define a constructor. A great book that might help is The GLib/GTK+ Development Platform. In chapter 3 you can find a good introduction to Semi-Object-Oriented Programming in C.
Here is a possible implementation, not necessarily the best one:
/src/main.c
#include <stdio.h>
#include "point.h"
int main()
{
Point *p1 = init(6, 7);
printf("%d\n", getX(p1));
printf("%d\n", getY(p1));
Point *p2 = init(12, 14);
printf("%d\n", getX(p2));
printf("%d\n", getY(p2));
setX(p2, 16);
printf("%d\n", getX(p2));
setY(p2, 16); /* error; we want y to initialize once and remain constant. Also accessing y with p2->y is an error too. */
printf("%d\n", getY(p2)); /* getY is ok */
freep(p1);
freep(p2);
}
/src/point.h
typedef struct _Point Point;
Point *init(int, int);
int getX(Point *);
void setX(Point *, int);
int getY(Point *);
void freep(Point *);
/src/point.c
#include <stdlib.h>
#include "point.h"
struct _Point{
int x;
int y;
};
Point *init(int x, int y)
{
Point *temp;
temp = malloc(sizeof(Point));
temp->x = x;
temp->y = y;
return temp;
}
int getX(Point *p)
{
return p->x;
}
void setX(Point *p, int x)
{
p->x = x;
}
int getY(Point *p)
{
return p->y;
}
void freep(Point *p)
{
free(p);
}
Furthermore, if we need a private method in our class, we do not provide a declaration of it in the header and also we use static to restrict its access within the class's file.
I have created a structure called Register, with around 8 fields within it. I now want to create a structure called Instrument, which should have a variable amount of of fields, 6 which are the same for every instrument, plus a certain amount of fields depending on how many registers are attributed to it. How can I create this?
For clarity here is what I would like to create (although may not be accurate).
typedef struct {
int x;
int y;
int z;
} Register;
typedef struct {
int x;
int y;
int z;
Register Reg1;
Register Reg2;
...
} Instrument;
You can make use of flexible array members to achieve the same.
Something like
typedef struct {
int x;
int y;
int z;
Register Reg1;
Register Reg2; //upto this is fixed....
Register Reg[];
} Instrument;
and then, you can allocate memory as needed to someVar.Reg later.
For an example, quoting C11, chapter ยง6.7.2.1/20
EXAMPLE 2 After the declaration:
struct s { int n; double d[]; };
the structure struct s has a flexible array member d. A typical way to use this is:
int m = /* some value */;
struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));
and assuming that the call to malloc succeeds, the object pointed to by p behaves, for most purposes, as if
p had been declared as:
struct { int n; double d[m]; } *p;
You can use pointers
typedef struct
{
int x;
int y;
int z;
Register *reg;
} Instrument;
use it into code
Instrument a.reg = malloc(sizeof(Register)*NUM_OF_REGISTERS);
if (a.reg != NULL)
{
// your STUFF
free(a.Reg);
}
is there a more compact way for using function pointers inside a struct ?
Do I really need to type defining the function pointer? I tried without but received type errors. Are there any hazards, or anything that I've done that is against good code practice?
#include <stdio.h>
#include <math.h>
void lineFunc(int* a)
{
int x1 = a[0];
int y1 = a[1];
int x2 = a[2];
int y2 = a[3];
double length = sqrtf( pow( (x1-x2),2 )+ pow((y1-y2),2) );
printf("%f\n", length);
}
void areaFunc(int* a)
{
int base = a[0];
int height = a[1];
int area = base*height;
printf("%d",area);
}
typedef void (*Operation)(int* a );
typedef struct CALC_TYPE
{
Operation opt
} CALC;
int main()
{
int lineArg[4] = {1 , 2, 3, 4}; //x1, y1, x2, y2
int areaArg[2] = {5,10}; // base, height
void (*lineCalc)(int*);
void (*areaCalc)(int*);
lineCalc = lineFunc;
areaCalc = areaFunc;
CALC line;
CALC area;
CALC* cmdArray = calloc(2,sizeof(CALC));
line.opt = lineFunc;
area.opt = areaFunc;
cmdArray[0]=line;
cmdArray[1]=area;
cmdArray[0].opt(lineArg);
cmdArray[1].opt(areaArg);
return 0;
}
is there a more compact way for using function pointers inside a struct ?
No.
Do I really need to type defining the function pointer?
No, but it makes your code much more readable because the notation for function pointers is arcane. You could have instead written.
typedef struct CALC_TYPE
{
void (*opt) (int*);
} CALC;
Are there any hazards, or anything that I've done that is against good code practice?
Not really. Making a struct that only contains 1 thing is questionable, but it's obviously a learning exercise.
The typedef Operation and some variables are useless. The struct too but If I've understood you, you want to keep it. So here is a more compacte way:
#include <stdio.h>
#include <math.h>
#include <stdlib.h> // calloc
void lineFunc(int* a)
{
// ...
}
void areaFunc(int* a)
{
// ...
}
typedef struct CALC_TYPE
{
void (*opt)(int *a);
} CALC;
int main()
{
int lineArg[4] = {1 , 2, 3, 4}; //x1, y1, x2, y2
int areaArg[2] = {5,10}; // base, height
CALC *cmdArray = calloc(2, sizeof(CALC));
cmdArray[0].opt = lineFunc;
cmdArray[1].opt = areaFunc;
cmdArray[0].opt(lineArg);
cmdArray[1].opt(areaArg);
free(cmdArray); // 1 malloc/calloc => 1 free
return 0;
}
EDIT:
Are there any hazards, or anything that I've done that is against good
code practice?
Include stdlib.h to use calloc
Don't forget to free dynamically allocated memory
Why pow then sqrtf then store in double ? Use sqrt instead
You could avoid the use of a struct here
One additional point that I did not see in the other answers concerns a benefit of struct usage: function prototype stability. Even if a struct starts out with a single variable, future requirements for the struct may force more variables to be added. Because of the way struct variables are passed as arguments, prototype's of functions written to use the original single single variable struct, will not be broken when additional variables are added.
For example, your struct can be defined as:
typedef struct CALC_TYPE
{
Operation opt
} CALC;
Or:
typedef struct CALC_TYPE
{
Operation opt
int a;
float b;
} CALC;
Without forcing change to a function that calls it.:
void func(CALC *c)
{
...
}
It's a great way to allow changes to the number of items that need to be passed as data without changing the argument list.
Using a modification of your area function, consider the following struct that was initially designed to support area measurements:
typedef struct
{
int length;
int width;
}DIM;
int areaFunc(DIM *d)
{
return d->length*d->width*d
}
Later a requirement for the struct to support volume forces the addition of a variable:
typedef struct
{
int length;
int width;
int height;
}DIM;
Adding the new variable to the struct does not break the existing areaFunc(), but also supports the new function:
int volumeFunc(DIM *d)
{
return d->length*d->width*d->height;
}
To explain more, I have two structures-'first' and 'second' having common variables 'jack' and 'jill'. I want to print jack via a pointer based on if-else condition.
I understand at the time of printing I have to typecast the void pointer. But whether the pointer points to struct a or b is decided on run time.
It is a basic C code. How to overcome this?
Code
#include <stdio.h>
int main(void)
{
typedef struct one
{
int jack;
float jill;
}a;
typedef struct two
{
int jack;
float jill;
char something;
int something1;
}b;
a first;
b second;
void *z;
if(1)
{
a* z;
z = &first;
printf("First one");
}
else
{
b* z;
z = &second;
printf("Second one");
}
printf("%d\n", z->jack);
return 0;
}
Error
prog.c:36:17: warning: dereferencing 'void *' pointer printf("%d\n", z->jack); prog.c:36:17: error: request for member 'jack' in something not a structure or union
You get a compiler warning since the compiler does not understand z->jack since z is a void * (note that the declarations a* z and b* z are not valid outside the scope of the if and else block).
To overcome this you can use a function printJack as shown in the following listing:
#include <stdio.h>
typedef struct one
{
int jack;
float jill;
}a;
typedef struct two
{
int jack;
float jill;
char something;
int something1;
}b;
void printJack(void *pStruct, int type)
{
switch (type)
{
case 1:
printf("jack: %d\n", ((a *)pStruct)->jack);
break;
default:
printf("jack: %d\n", ((b *)pStruct)->jack);
break;
}
}
/*
** main
*/
int main(void)
{
a first;
b second;
void *z;
first.jack = 5;
second.jack = 4892;
printJack(&first, 1);
printJack(&second, 0);
z = &first;
printJack(z, 1);
return (0);
}
I've written code like this often and experienced a lot of trouble with it. Not at the time of implementing, since you are knowing what you are typing at that moment but let's say a few years later if you need to extend your code. You will miss a few places where you cast from void * to a * or b * and you'll spend a lot of time debugging what's going on...
Now I'm writing things like this in the following way:
#include <stdio.h>
typedef struct header
{
int jack;
float jill;
} h;
typedef struct one
{
struct header header;
/* what ever you like */
}a;
typedef struct two
{
struct header header;
char something;
int something1;
/* and even more... */
}b;
void printJack(void *pStruct)
{
printf("jack: %d\n", ((struct header *)pStruct)->jack);
}
/*
** main
*/
int main(void)
{
a first;
b second;
void *z;
first.header.jack = 5;
second.header.jack = 4892;
printJack(&first);
printJack(&second);
v = &first;
printJack(v);
return (0);
}
As you've noticed I have declared a new struct header which covers the the common parts of struct one and struct two. Instead of casting the void * to either a * or b * a "common" cast to struct header * (or h *) is done.
By doing so you can easily extend the "common attribtues" of the structs or you can implement further structs using this header and function printJack still will work. Additionally there is no need for attribute type anymore making is easier to call printJack. You can even change the type of jack without needing to change it in various places within your code.
But remember that struct header needs to be the first element of the structs you use this mechanism. Otherwise you will end up with a few surprises since you are using memory which does not contain the data of the struct header...
I have the following code:
typedef struct {
double x, y;
} point_t ;
typedef struct {
point_t a, b, c;
} triangle_t;
int read_point(point_t * const point) {
int status = scanf(" (&lf,&lf)", &point_t.x, &point_t.y);
return(status);
}
I'm trying to read an x and y coordinate that the user enters for the vertexes of a triangle (Points a, b and c.) However, I'm getting a weird error underlining both instances of "point_t" in the scanf function.
Type name is not allowed.
What's going on?
Change it to:
int status = scanf(" (%lf,%lf)", &(point->x), &(point->y));
Remember to use the variable name point, not the type name point_t. It also important to note that you must use the operator -> on pointer types (it is equivalent to dereferencing it and then using the member operator [p->x == (*p).x]).
try this code
typedef struct {
double x;
double y;
} point_t ;
typedef struct {
point_t a;
point_t b
point_t c;
} triangle_t;
int read_point(point_t * point) {
int status = scanf(" (&lf,&lf)", point->x, point->y);
return(status);
}
I think in struct, you should declare each field with it's type; multiple declaration as int x,y doesn't work.
Secondly, you are passing a pointer so to access you should use the name of your argument ( "point" is this case) this way point->field or (*point).field and not &point !