Discussion around functionpointers in array of structs. What are good practises? - c

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;
}

Related

Init a const var in a struct after the struct variable is created

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.

Emulating Classes in C using Structs

I am constrained to using C for a competition and I have a need to emulate classes. I am trying to construct a simple "point" class that can return and set the X and Y coordinates of a point. Yet, the below code returns errors such as "unknown type name point", "expected identifier or (" and "expected parameter declarator." What do these errors mean? How do I correct them? Is this the correct approach to writing a "pseudo-class"?
typedef struct object object, *setCoordinates;
struct object {
float x, y;
void (*setCoordinates)(object *self, float x, float y);
void (*getYCoordinate)(object *self);
void (*getXCoordinate)(object *self);
};
void object_setCoordinates(object *self, float x, float y){
self->x = x;
self->y = y;
}
float object_getXCoordinate(object *self){
return self->x;
}
float object_getYCoordinate(object *self){
return self->y;
}
object point;
point.setCoordinates = object_setCoordinates;
point.getYCoordinate = object_getYCoordinate;
point.getXCoordinate = object_getXCoordinate;
point.setCoordinates(&point, 1, 2);
printf("Coordinates: X Coordinate: %f, Y Coordinate: %f", point.getXCoordinate, point.getYCoordinate);
Reference:
1. C - function inside struct
2. How do you implement a class in C?
You would do much better to implement it as follows:
#include <stdio.h>
struct point {
float x;
float y;
};
void point_setCoordinates(struct point *self, float x, float y){
self->x = x;
self->y = y;
}
float point_getXCoordinate(struct point *self){
return self->x;
}
float point_getYCoordinate(struct point *self){
return self->y;
}
int main(void) {
struct point my_point;
point_setCoordinates(&my_point, 1, 2);
printf("Coordinates: X Coordinate: %f, Y Coordinate: %f\n",
point_getXCoordinate(&my_point),
point_getYCoordinate(&my_point));
return 0;
}
A few things to note:
As #Olaf has pointed out, never typedef a pointer - it hides your intent and makes things unclear. Yes, it's all over poor APIs (e.g: Windows), but it reduces readability.
You really don't need these functions to be the equivalent to virtual functions... just have a set of point_*() functions that you call on the point 'thing'.
Don't confuse things with poor names... if it's an X,Y point, then call it such - not an object (which is a very generic concept).
You need to call functions... in your call to printf() you used point.getXCoordinate - that is to say you took it's address and asked printf() to display it as though it were a float
You might start to wonder why you'd care about calling a function to get access to a variable that is inside a transparent struct... See below.
Many libraries / APIs provide opaque datatypes. This means that you can get a 'handle' to a 'thing'... but you have no idea what's being stored within the 'thing'. The library then provides you with access functions, as shown below. This is how I'd advise you approach the situation.
Don't forget to free the memory!
I've implemented an example below.
point.h
#ifndef POINT_H
#define POINT_H
struct point;
struct point *point_alloc(void);
void point_free(struct point *self);
void point_setCoordinates(struct point *self, float x, float y);
float point_getXCoordinate(struct point *self);
float point_getYCoordinate(struct point *self);
#endif /* POINT_H */
point.c
#include <stdlib.h>
#include <string.h>
#include "point.h"
struct point {
float x;
float y;
};
struct point *point_alloc(void) {
struct point *point;
point = malloc(sizeof(*point));
if (point == NULL) {
return NULL;
}
memset(point, 0, sizeof(*point));
return point;
}
void point_setCoordinates(struct point *self, float x, float y) {
self->x = x;
self->y = y;
}
float point_getXCoordinate(struct point *self) {
return self->x;
}
float point_getYCoordinate(struct point *self) {
return self->y;
}
void point_free(struct point *self) {
free(self);
}
main.c
#include <stdio.h>
#include "point.h"
int main(void) {
struct point *point;
point = point_alloc();
point_setCoordinates(point, 1, 2);
printf("Coordinates: X Coordinate: %f, Y Coordinate: %f\n",
point_getXCoordinate(point),
point_getYCoordinate(point));
point_free(point);
return 0;
}
Your code has some minor errors. That's why it doesn't compile.
Fixed here:
typedef struct object object;
struct object {
float x, y;
void (*setCoordinates)(object *self, float x, float y);
float (*getYCoordinate)(object *self);
float (*getXCoordinate)(object *self);
};
void object_setCoordinates(object *self, float x, float y){
self->x = x;
self->y = y;
}
float object_getXCoordinate(object *self){
return self->x;
}
float object_getYCoordinate(object *self){
return self->y;
}
int main()
{
object point;
point.setCoordinates = object_setCoordinates;
point.getYCoordinate = object_getYCoordinate;
point.getXCoordinate = object_getXCoordinate;
point.setCoordinates(&point, 1, 2);
printf("Coordinates: X Coordinate: %f, Y Coordinate: %f",
point.getXCoordinate(&point), point.getYCoordinate(&point));
}
As for the approach, there's probably no need to store the pointers to your methods inside the struct when you can simply call them directly:
object x;
object_setCoordinates(x, 1, 2);
//...
I also have an example of basic class emulation in C [the OP specified for a specific application, although, this answer is to the general question]:
A header file called "c_class.h"
#ifndef CLASS_HEADER_H
#define CLASS_HEADER_H
// Function pointer prototypes used by these classes
typedef int sub_func_t (int);
typedef float sub_funcf_t (int,int);
/* class type definition
(emulated class type definition; C doesn't really have class types) */
typedef struct {
//Data Variables
int a;
/*Function (also known as Method) pointers
(note that different functions have the same function pointer prototype)*/
sub_func_t* add;
sub_func_t* subt;
sub_func_t* mult;
sub_funcf_t* div;
} class_name;
// class init prototypes
// These inits connect the function pointers to specific functions
// and initialize the variables.
class_name* class_init_ptr (int, sub_func_t*, sub_func_t*, sub_func_t*, sub_funcf_t*);
class_name class_init (int, sub_func_t*, sub_func_t*, sub_func_t*, sub_funcf_t*);
#endif
A source code file called "c_class.c"
//gcc -o c_class c_class.c
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"c_class.h"
// The class function definitions.
/*
If we make these member functions static then they are only
accessible via code from this file.
However, we can still pass the class-like objects around a
larger program and access their member functions,
just like in any OO language.
It is possible to emulate inheritance by declaring a class object
from the class type definition (I don't touch on these more
abstract subjects though, this is only a basic class emulation).
*/
static int AddFunc(int num){
num++;
return num;
}
static int SubtFunc(int num){
num--;
return num;
}
static int MultFunc(int num){
num *= num;
return num;
}
static float DivFunc(int num, int denom){
float fnum = (float)num / (float)denom;
return fnum;
}
// The class init function definitions.
class_name* class_init_ptr (int num, sub_func_t* addition, sub_func_t* subtraction, sub_func_t* multiplication, sub_funcf_t* division)
{
class_name* new_class = malloc(sizeof(*new_class));
assert(new_class != NULL);
*new_class = (class_name){num, addition, subtraction, multiplication, division};
/*We could also just type:
new_class->a = num;
new_class->add = addition;
new_class->subt = subtraction;
new_class->mult = multiplication;
new_class->div = division;
*/
return new_class;
}
class_name class_init(int num, sub_func_t* addition, sub_func_t* subtraction, sub_func_t* multiplication, sub_funcf_t* division)
{
class_name new_class;
new_class = (class_name){num, addition, subtraction, multiplication, division};
/* We could also just type:
new_class.a = num;
new_class.add = addition;
new_class.subt = subtraction;
new_class.mult = multiplication;
new_class.div = division;
*/
return new_class;
}
//Working Function Prototypes
class_name* Working_Function(class_name*);
class_name Working_Function_Two(class_name);
int main(){
/* It's possible to connect the functions within the init also,
w/o sending them. */
class_name *MyClass = class_init_ptr(5, AddFunc, SubtFunc, MultFunc, DivFunc);
class_name MyOtherClass = class_init(0, AddFunc, SubtFunc, MultFunc, DivFunc);
printf("%i\n",MyClass->add(100));// 101
printf("%i\n",MyClass->subt(100));// 99
printf("%i\n",MyClass->mult(100));// 10000
printf("%f\n",MyClass->div(MyClass->a,2)); // 2.5
printf("%i\n",MyClass->mult(MyClass->mult(100))); //100000000
MyClass = Working_Function(MyClass);
//This would work also (because we're passing a pointer):
//Working_Function(MyClass);
printf("%i\n",MyClass->a); //a = 5000
MyOtherClass = Working_Function_Two(MyOtherClass);
printf("%i\n",MyOtherClass.a); //a = 9999
MyOtherClass.a = 25;
Working_Function_Two(MyOtherClass); //pass by value
printf("%i\n",MyOtherClass.a); //a = 25 (no value change)
Working_Function(&MyOtherClass); //pass by reference
printf("%i\n",MyOtherClass.a); //a = 5000 (value changed)
return 0;
}
//Working Functions
class_name* Working_Function(class_name* PassedClass){
printf("%i\n",PassedClass->a);// 5, then 25
printf("%i\n",PassedClass->add(PassedClass->a));// 6, then 26
PassedClass->a = 5000;
return PassedClass;
}
class_name Working_Function_Two(class_name PassedClass){
printf("%i\n",PassedClass.a);// 0, then 25
printf("%i\n",PassedClass.add(PassedClass.a));// 1, then 26
PassedClass.a = 9999;
return PassedClass;
}
/* We're passing emulated class objects and emulated class pointers
by reference and value, if everything works it should print this:
101
99
10000
2.500000
100000000
5
6
5000
0
1
9999
25
26
25
25
26
5000
*/
Another way to write a pseudo-class that needs polymorphism, with less overhead per instance, is to create a single virtual function table and have your constructor or factory function set that. Here’s a hypothetical example. (Edit: Now a MCVE, but for real code, refactor into header and separate source files.)
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
struct point; // Abstract base class.
struct point_vtable {
void (*setCoordinates)(struct point *self, float x, float y);
float (*getYCoordinate)(const struct point *self);
float (*getXCoordinate)(const struct point *self);
};
typedef struct point {
const struct point_vtable* vtable;
} point;
typedef struct cartesian_point {
const struct point_vtable* vtable;
float x;
float y;
} cartesian_point;
typedef struct polar_point {
const struct point_vtable* vtable;
float r;
float theta;
} polar_point;
void cartesian_setCoordinates( struct point* self, float x, float y );
float cartesian_getXCoordinate(const struct point* self);
float cartesian_getYCoordinate(const struct point* self);
void polar_setCoordinates( struct point* self, float x, float y );
float polar_getXCoordinate(const struct point* self);
float polar_getYCoordinate(const struct point* self);
const struct point_vtable cartesian_vtable = {
.setCoordinates = &cartesian_setCoordinates,
.getXCoordinate = &cartesian_getXCoordinate,
.getYCoordinate = &cartesian_getYCoordinate
};
const struct point_vtable polar_vtable = {
.setCoordinates = &polar_setCoordinates,
.getXCoordinate = &polar_getXCoordinate,
.getYCoordinate = &polar_getYCoordinate
};
void cartesian_setCoordinates( struct point* const self,
const float x,
const float y )
{
assert(self->vtable == &cartesian_vtable);
struct cartesian_point * const this = (struct cartesian_point*)self;
this->x = x;
this->y = y;
}
float cartesian_getXCoordinate(const struct point* const self)
{
assert(self->vtable == &cartesian_vtable);
const struct cartesian_point * const this = (struct cartesian_point*)self;
return this->x;
}
float cartesian_getYCoordinate(const struct point* const self)
{
assert(self->vtable == &cartesian_vtable);
const struct cartesian_point * const this = (struct cartesian_point*)self;
return this->y;
}
void polar_setCoordinates( struct point* const self,
const float x,
const float y )
{
assert(self->vtable == &polar_vtable);
struct polar_point * const this = (struct polar_point*)self;
this->theta = (float)atan2((double)y, (double)x);
this->r = (float)sqrt((double)x*x + (double)y*y);
}
float polar_getXCoordinate(const struct point* const self)
{
assert(self->vtable == &polar_vtable);
const struct polar_point * const this = (struct polar_point*)self;
return (float)((double)this->r * cos((double)this->theta));
}
float polar_getYCoordinate(const struct point* const self)
{
assert(self->vtable == &polar_vtable);
const struct polar_point * const this = (struct polar_point*)self;
return (float)((double)this->r * sin((double)this->theta));
}
// Suitable for the right-hand side of initializations, before the semicolon.
#define CARTESIAN_POINT_INITIALIZER { .vtable = &cartesian_vtable,\
.x = 0.0F, .y = 0.0F }
#define POLAR_POINT_INITIALIZER { .vtable = &polar_vtable,\
.r = 0.0F, .theta = 0.0F }
int main(void)
{
polar_point another_point = POLAR_POINT_INITIALIZER;
point* const p = (point*)&another_point; // Base class pointer.
polar_setCoordinates( p, 0.5F, 0.5F ); // Static binding.
const float x = p->vtable->getXCoordinate(p); // Dynamic binding.
const float y = p->vtable->getYCoordinate(p); // Dynamic binding.
printf( "(%f, %f)\n", x, y );
return EXIT_SUCCESS;
}
This takes advantage of the guarantee that the common initial subsequence of structs can be addressed through a pointer to any of them, and stores only one pointer of class overhead per instance, not one function pointer per virtual function. You can use the virtual table as your class identifier for your variant structure. Also, the virtual table cannot contain garbage. Virtual function calls need to dereference two pointers rather than one, but the virtual table of any class in use is highly likely to be in the cache.
I also note that this interface is very skeletal; it’s silly to have a polar class that can do nothing but convert back to Cartesian coordinates, and any implementation like this would at minimum need some way to initialize dynamic memory.
If you don’t need polymorphism, see Attie’s much simpler answer.

How to typecast void pointer based on condition?

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...

Pointer to a struct array

How can I make a pointer to a member of a struct, thats an array of ints. This is how the struct looks like:
typedef struct {
volatile int x[COORD_MAX];
volatile int y[COORD_MAX];
volatile int z[COORD_MAX];
//... other variables
} coords;
coords abc;
abc is a global variable.
Now, I would like to get pointers to x,y and z arrays and save them to another array. Then acces them through passing a wanted index. Here is what I mean:
void test(int index1, int index2)
{
static volatile const int* coords_ptr[3] = {abc.x, abc.y, abc.z};
coords_ptr[index1][index2] = 100;
}
So index1 would select which type of coordinates to choose from (x,y,z). And index2 would select which index of the coordinates to change.
Please note, that this is just a simplification of the code I am working on. But the principle is the same.
Thanks in advance!
EDIT:
I've written wrong code. Sorry for the confusion, this should be right now.
There's only one small mistake: you made the pointers point to const volatile int, which prevents you from writing to them.
Just write
static volatile int* coords_ptr[3] = {abc.x, abc.y, abc.z};
and it'll work.
#include <stdio.h>
#define COORD_MAX 3
typedef struct {
volatile int x[COORD_MAX];
volatile int y[COORD_MAX];
volatile int z[COORD_MAX];
} coords;
coords abc;
void test(int index1, int index2)
{
static volatile int* coords_ptr[3] = {abc.x, abc.y, abc.z};
coords_ptr[index1][index2] = 100;
}
int main()
{
test(0, 0);
test(1, 1);
printf("%i %i\n", abc.x[0], abc.y[1]);
return 0;
}
output:
100 100

Casting of structures in C when first fields are not aligned

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.

Resources