I looked but couldn't find a direct reference for this question. I'm new to function pointers (and C), so I don't know all the tricks one can do yet :)
I've effectively got a function:
void select_comparator(My_Struct *structure, int (*comp)(int x, int y)) {
...
...where My_Struct has prototype:
typedef struct my_struct {
int (*comp)(int x, int y);
} My_Struct;
Modulo some minor details. I just want to know if the following is correct syntax:
void select_comparator(My_Struct *structure, int (*comp)(int x, int y)) {
structure->comp = comp;
}
It seems almost too easy, and I'm worried it is.
Nothing's wrong: this is the basis of callbacks in c. Just make sure the signature of your function pointer matches the type defined in your structure. Where it gets remotely tricky is when you're using this in a large project, and people forget to check if the function pointer is valid or void, along with arguments, etc.
Code Listing
/*******************************************************************************
* Preprocessor directives.
******************************************************************************/
#include <stdio.h>
/*******************************************************************************
* Data types.
******************************************************************************/
typedef struct my_struct {
int (*comp)(int x, int y);
} My_Struct;
/*******************************************************************************
* Function prototypes.
******************************************************************************/
int c(int a, int b);
void select_comparator(My_Struct *structure, int (*comp)(int x, int y));
/*******************************************************************************
* Function definitions.
******************************************************************************/
/*----------------------------------------------------------------------------*/
int main(void)
{
My_Struct s;
select_comparator(&s, &c);
s.comp(1, 2);
return 0;
}
/*----------------------------------------------------------------------------*/
void select_comparator(My_Struct *structure, int (*comp)(int x, int y))
{
structure->comp = comp;
}
/*----------------------------------------------------------------------------*/
int c(int a, int b)
{
int ret = 0;
if (a < b) {
ret = (-1);
} else if (a > b) {
ret = 1;
}
return ret;
}
The code is ok.
Though note that function pointers have plain horrible syntax in C, particularly when passed to/returned from functions. Try writing something like "function returning function-pointer and taking function-pointer as parameter" and you'll soon realize that the syntax is pure madness.
It is therefore a good idea to make function pointers "fall in line" with the rest of the language by using typedefs.
You code could be written like this:
typedef int comp_t (int x, int y); // typedef a function type
typedef struct {
comp_t* comp; // pointer to such a function type
} My_Struct;
void select_comparator(My_Struct *structure, comp_t* comp) {
structure->comp = comp;
}
Now the code turns easier to read and the function pointer behaves pretty much like any other pointer.
I'm trying to get the size of a struct that was defined in a different source file (other.c) to keep it hidden.
In the other.h:
typedef struct X x_t;
In the other.c:
struct X{
int y;
int z;
};
Now I want in the main.c to get the size of this struct.
#include "other.h"
int main(){
x_t *my_x;
my_x = malloc(sizeof(struct x_t));
return 0;}
But this gives me following error:
error: invalid application of ‘sizeof’ to incomplete type ‘struct x_t’
Can anybody help me? Thank you!
The whole purpose of having a hidden struct is to carefully control their construction, their destruction, and access to the contents.
Functions to construct, destruct, get the contents, and set the contents have to be provided to make the hidden struct useful.
Here's an example of what the .h and .c files could be:
other.h:
typedef struct X x_t;
x_t* construct_x(void);
void destruct_x(x_t* x);
void set_y(x_t* x, int y);
int get_y(x_t* x);
void set_z(x_t* x, int z);
int get_z(x_t* x);
other.c:
struct X {
int y;
int z;
};
x_t* construct_x(void)
{
return malloc(sizeof(x_t));
}
void destruct_x(x_t* x)
{
free(x);
}
void set_y(x_t* x, int y)
{
x->y = y;
}
int get_y(x_t* x)
{
return x->y;
}
void set_z(x_t* x, int z)
{
x->z = z;
}
int get_z(x_t* x)
{
rteurn x->z;
}
When I try to compile a C file under 64-bit Linux using command:
gcc -o strain_from_faults_new strain_from_faults_new.c gen.h eqf.h
I met the following errors:
eqf.h:16:3: error: unknown type name ‘Point’
Point loc;
^
eqf.h:32:3: error: unknown type name ‘Point’
Point p[33];
^
eqf.h:44:3: error: unknown type name ‘Point’
Point p[33];
^
eqf.h:61:3: error: unknown type name ‘Point’
Point xy[NSEG];
^
It seems that type 'Point' is not defined, but it does defined in the file
gen.h
struct point {
double x;
double y;
};
typedef struct point Point;
I don't know why it have such an error, since this C file can be compiled in other computers. Is this 32bit-64bit compatible issue?
Any comment(s) would be highly appreciated!
According to the comments I #include "gen.h" in eqf.h file, but it not doing well. Since the two head files gen.h eqf.h have already been included in the C file strain_from_faults_new.c, the compiler have errors:
In file included from eqf.h:12:0,
from strain_from_faults_new.c:6:
gen.h:11:8: error: redefinition of ‘struct point’
struct point {
^
In file included from strain_from_faults_new.c:5:0:
gen.h:11:8: note: originally defined here
struct point {
^
Does anybody have any ideas?
Well, following are the entire codes:
gen.h
#define MAX_NAME 50
#define MAXNAME 50
#define EARTH_RADIUS 6371.0
#define MU (3.0e11)
#define PI 3.1415927
#define D2R 0.0174532
#define SUNIT (1.0e-9)
#define KAPA 0.25
#include <stdio.h>
struct point {
double x;
double y;
};
typedef struct point Point;
extern int enclose(Point *, int, Point);
extern int enclose2(Point *, int, Point, Point);
extern int lenclose(Point *p, int n, Point p1);
extern int lenclose2(Point *p, int n, Point p1, Point p2);
extern double azimuth(double, double);
extern double atan2d(double, double);
extern double sind(double);
extern double cosd(double);
extern double dsign(double);
extern double dmax(double, double);
extern double dmin(double, double);
extern double diag_len(Point p[]);
extern void make_tensor(double z[][3], double, double, double);
extern void read_a_line(FILE *);
extern void strip_a_line(FILE *);
extern char *get_a_string(FILE *f, char* str);
extern int line_to_string(FILE *f, char* str);
extern int in_region(int node[], int N, int p);
extern double convert_date_to_year(int);
eqf.h
#define MAXP 10
#define MAXN 400
#define MAXB 1000
#define MAXF 37000
#define MAXE 1000
#define TYPE_F 1
#define TYPE_E 0
#define T 149
#define DEPTH 15.0
#define NSEG 2074
#include <stdio.h>
#include "gen.h"
struct earthquake {
int date;
Point loc;
double mom[3][3];
double m0;
int type;
};
struct merr {
double m[3][3];
};
struct mom {
double m0;
double mxx;
double myy;
double mxy;
};
struct region {
Point p[33];
double area;
double t0;
struct earthquake event[50];
int ne;
struct earthquake *e[100];
double strainrate[9];
double strain[9];
double strainr[9];
double strain0[9];
};
struct regionf {
Point p[33];
double area;
int ix;
int iy;
int ia;
};
struct fault {
double strike;
double rake;
double dip;
double rate;
double ratemin;
double ratemax;
char name[50];
int date;
int n;
Point xy[NSEG];
};
extern void test();
extern void read_faults(FILE *inf, struct fault *f);
extern void test_mom();
extern void print_event (FILE *inf, struct earthquake e);
extern int bydate(struct earthquake *, struct earthquake *);
extern void sort_event(FILE *);
extern int write_mom_tensor(struct earthquake *, int *, double);
extern void fill_regionf(struct regionf *, int *);
extern void fill_region(struct region *, int *);
extern void print_mom_in_region(struct region *b, int nb);
extern double strain_rate(double ex, double ey, double exy);
extern double strain_rate_var(double ex, double ey, double exy, double dex, double dey, double dexy, double cxy, double cxxy, double cyxy);
strain_from_faults_new.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "gen.h"
#include "eqf.h"
void deal_with_options(int, char **);
int no_faults, n_events;
double sdepth;
double ub = 0.01;
char faultin[25];
FILE *strain1;
int main(int argc, char *argv[]) {
Point p[MAXN], p1[10];
struct fault f[MAXF];
struct regionf b[MAXB];
double plat=0.0, plon=0.0, prat=0.0;
int n=0, i, j, nb=0, np, num, ia, k, l, nrect=0, nfree=0, ix=0, iy=0;
FILE *faults, *strain0;
sdepth = DEPTH*1.0e5;
strcpy(faultin, "fault.in");
deal_with_options(argc, argv);
if( (faults = fopen(faultin, "r")) == NULL ) {
printf("Error: File %s does not exist.\n", faultin);
exit(-1);
}
if( (strain0 = fopen("spline_fit.dat", "r")) == NULL) {
printf("Error: File spline_fit.dat cannot open\n");
exit(-1);
}
if( (strain1 = fopen("strain_from_faults.dat", "w")) == NULL) {
printf("Error: File strain_from_faults.dat cannot open\n");
exit(-1);
}
fscanf(strain0, "%d%d%d", &ix, &iy, &num);
fscanf(strain0, "%d", &nfree);
fprintf(strain1, "%10d %10d %10d\n", ix, iy, num);
fprintf(strain1, "%10d\n", nfree);
for(i=nfree; i<num; i++) {
if(fscanf(strain0, "%d%lf%lf%lf", &np, &plat, &plon, &prat) != 4) {
printf("Error: format error in spline_fit.dat\n");
exit(1);
}
fprintf(strain1, "%10d %10.3f %10.3f %12.6e\n", np, plat, plon, prat);
}
fscanf(strain0, "%d", &nrect);
fprintf(strain1, "%10d\n", nrect);
close(strain0);
for(i = 0; i < nrect; i += MAXB) {
nb = i;
printf("Working on regions %d to %d ...\n", i, i+MAXB);
fill_regionf(b, &nb);
read_clip_faults(faults, f, b, nb);
}
return 0;
}
int read_clip_faults(FILE *inf, struct fault *f, struct regionf *b, int nb) {
int i, j, k, l, ib, jj, kk, ii, n, nf;
double x, y, dx, dy, d, mt[3][3], c, theta;
double sd, md, strainrate[9];
double clip_seg = 0.05;
struct mom m1;
struct mom m0;
struct merr m2;
struct fault f0;
Point p[100], p0;
i=0;
fseek(inf, 0, SEEK_SET);
while( (k = fscanf(inf, "%d%lf%lf%lf%lf%lf%s",
&n, &(f[i].rake), &(f[i].dip), &(f[i].ratemin),
&(f[i].rate), &(f[i].ratemax), f[i].name)) == 7) {
printf("Fault no. %d, %s\n", i, f[i].name);
f[i].rate = f[i].rate;
f[i].ratemin = f[i].ratemin;
f[i].ratemax = f[i].ratemax;
f[i].n = 0;
for(j=0; j<n; j++) {
if( (l = fscanf(inf, "%lf%lf", &(p[j].y), &(p[j].x))) != 2) {
printf("Error at fault %s, line %d in fault.in\n", f[i].name, j);
exit(1);
}
}
jj=0;
for(j=0; j<n-1; j++) {
k = 0;
while( k < nb && (l = enclose(b[k].p, 33, p[j])) == 0)
...
Following Mike Kinghan's comments, I added
#ifndef GEN_H
#define GEN_H
and
#endif
in the head and tail of the gen.h file, respectively. But it not doing well, here are the errors:
/tmp/ccteT25z.o: In function `read_clip_faults':
strain_from_faults_new.c:(.text+0x6a4): undefined reference to `enclose'
strain_from_faults_new.c:(.text+0x7c5): undefined reference to `enclose'
strain_from_faults_new.c:(.text+0xa14): undefined reference to `enclose'
strain_from_faults_new.c:(.text+0xa7b): undefined reference to `dsign'
strain_from_faults_new.c:(.text+0xaae): undefined reference to `dsign'
strain_from_faults_new.c:(.text+0xad9): undefined reference to `dsign'
strain_from_faults_new.c:(.text+0xb5a): undefined reference to `dsign'
...
you need to #include "gen.h" in eqf.h
If you read this:
In file included from eqf.h:12:0,
from strain_from_faults_new.c:6:
gen.h:11:8: error: redefinition of ‘struct point’
struct point {
^
In file included from strain_from_faults_new.c:5:0:
gen.h:11:8: note: originally defined here
struct point {
^
it tells you that struct point is defined twice in the same translation
unit, strain_from_faults_new.c, which is an error.
You have defined struct point in gen.h at line 11.
You have included gen.h at line 5 in strain_from_faults_new.c
You have also included gen.h at line 12 in eqf.h.
And finally you have included eqf.h at line 6 in strain_from_faults_new.c,
thereby including the definition of struct point again.
To avoid such problems, use header guards a.k.a include guards in every header you write,
e.g.
gen.h
#ifndef GEN_H
#define GEN_H
struct point {
double x;
double y;
};
typedef struct point Point;
#endif
This makes it harmless to include a header more than once in a translation unit.
And, don't pass header files in the compiler commandline:
gcc -o strain_from_faults_new strain_from_faults_new.c gen.h eqf.h
^^^^^ ^^^^^
A header file gets compiled by being #include-ed in a .c file, which
copies it into the translation unit.
You need to add #include "gen.h" in eqf.h and compile your program with the command:
gcc -o gen.h eqf.h strain_from_faults_new strain_from_faults_new.c;
Compiler will compile your program file according to your file input order.
If I have a struct in C that has an integer and an array, how do I initialize the integer to 0 and the first element of the array to 0, if the struct is a member another struct so that for every instance of the other struct the integer and the array has those initialized values?
Initialisers can be nested for nested structs, e.g.
typedef struct {
int j;
} Foo;
typedef struct {
int i;
Foo f;
} Bar;
Bar b = { 0, { 0 } };
I hope this sample program helps....
#include <stdio.h>
typedef struct
{
int a;
int b[10];
}xx;
typedef struct
{
xx x1;
char b;
}yy;
int main()
{
yy zz = {{0, {1,2,3}}, 'A'};
printf("\n %d %d %d %c\n", zz.x1.a, zz.x1.b[0], zz.x1.b[1], zz.b);
return 0;
}
yy zz = {{0, {0}}, 'A'}; will initialize all the elements of array b[10] will be set to 0.
Like #unwind suggestion, In C all instances created should initialized manually. No constructor kind of mechanism here.
You can 0-initialize the whole struct with {0}.
For example:
typedef struct {
char myStr[5];
} Foo;
typedef struct {
Foo f;
} Bar;
Bar b = {0}; // this line initializes all members of b to 0, including all characters in myStr.
C doesn't have constructors, so unless you are using an initializer expression in every case, i.e. write something like
my_big_struct = { { 0, 0 } };
to initialize the inner structure, you're going to have to add a function and make sure it's called in all cases where the structure is "instantiated":
my_big_struct a;
init_inner_struct(&a.inner_struct);
Here is an alternative example how you would do things like this with object-oriented design. Please note that this example uses runtime initialization.
mystruct.h
#ifndef MYSTRUCT_H
#define MYSTRUCT_H
typedef struct mystruct_t mystruct_t; // "opaque" type
const mystruct_t* mystruct_construct (void);
void mystruct_print (const mystruct_t* my);
void mystruct_destruct (const mystruct_t* my);
#endif
mystruct.c
#include "mystruct.h"
#include <stdlib.h>
#include <stdio.h>
struct mystruct_t // implementation of opaque type
{
int x; // private variable
int y; // private variable
};
const mystruct_t* mystruct_construct (void)
{
mystruct_t* my = malloc(sizeof(mystruct_t));
if(my == NULL)
{
; // error handling needs to be implemented
}
my->x = 1;
my->y = 2;
return my;
}
void mystruct_print (const mystruct_t* my)
{
printf("%d %d\n", my->x, my->y);
}
void mystruct_destruct (const mystruct_t* my)
{
free( (void*)my );
}
main.c
int main (void)
{
const mystruct_t* x = mystruct_construct();
mystruct_print(x);
mystruct_destruct(x);
return 0;
}
You don't necessarily need to use malloc, you can use a private, statically allocated memory pool as well.
In api.h
typedef void* hidden_my_type;
void do_something(my_type x);
In core.c
struct _my_type
{
int a;
}
void do_something(hidden_my_type void_x)
{
struct *_my_type x = void_x; /*Don't understand is that correct way to do, as I'm getting segmentation fault error */
printf("Value: %d\n", x->a);
}
Other way I thought as,
struct *_my_type x = (struct _my_type *)malloc(sizeof(struct _my_type));
void_x = x
printf(Value: %d\n", x->a);
But still I'm getting seg-fault error.
ok here is the problem with void*....
e.g.
in core.c
void init_my_type(hidden_my_type a)
{
my_type *the_a = malloc(...);
a = the_a // <<<<<<<<<<<<<<<<<<<<<<<<<<<< is this correct?! a is void* and the_a // is original type
pthread_cond_init(&the_a->...);
.. (in short any other methods for init ..)
}
void my_type_destroy(my_hidden_type x)
{
my_type *the_x = x;
pthread_detroy(&the_x-> ...);
}
in main.c
test()
{
my_hidden_type x;
init_my_type(x);
....
my_type_detroy(x);
}
this it self should fail. as in main.c test function, x is void* ... init will allocate but in destroy I'm again passing void* .. which can be anything!
EDIT (Solved for me)
In api.h
typedef void* hidden_my_type;
void do_something(my_type x);
In core.c
struct _my_type
{
int a;
}
void init_hidden_type(hidden_my_type void_p_my_type)
{
struct _my_type *real_my_type = (struct _my_type *)malloc(sizeof(struct _my_type));
//--- Do init for your type ---
void_p_my_type = real_my_type;
}
void do_something(hidden_my_type void_x)
{
struct *_my_type x = void_x;
printf("Value: %d\n", x->a);
}
Version 0 — Critique of Question's Code
The posted code does not compile.
api.h
typedef void* hidden_my_type;
void do_something(my_type x);
This defines hidden_my_type but not the my_type that is passed to do_something(). Presumably, you intended:
typedef void *my_type;
void do_something(my_type x);
core.c
struct _my_type
{
int a;
}
As noted below too, there is a semi-colon missing after the structure definition.
void do_something(hidden_my_type void_x)
{
struct *_my_type x = void_x;
printf("Value: %d\n", x->a);
}
You have the hidden_my_type vs my_type problem again. You have the * of the pointer where it cannot go; it must go after the struct _my_type. You probably intended something like:
void do_something(my_type void_x)
{
struct _my_type *x = void_x;
printf("Value: %d\n", x->a);
}
This is now syntactically correct (I think; I haven't actually run it past a compiler). You have not shown how it is used; indeed, since the user code has no way to generate a pointer to a valid structure, there is no way for this code to be used safely.
Your test code (unshown — why don't you show your test code) might look something like this:
#include "api.h"
int main(void)
{
my_type x = 0;
do_something(x);
return 0;
}
Alternatively, it might not have the = 0 initializer in place. Either way, your code is unable to function sanely, and a core dump is almost inevitable. When you hide the structure from the user, you have to provide them with a mechanism to get hold of a valid (pointer to) the structure, and you've not done that.
Version 1
This is a better way to do it, because it is more nearly type-safe:
api.h version 1
typedef struct _my_type *my_type;
void do_something(my_type x);
core.c version 1
#include "api.h"
struct _my_type
{
int a;
};
Note the added semi-colon, and the include of the api.h file.
void do_something(my_type x)
{
// Now you don't have to do casting here!
//struct *_my_type x = void_x; /*Don't understand is that correct way to do, as I'm getting segmentation fault error */
printf("Value: %d\n", x->a);
}
Version 2
Actually, we can debate the wisdom of hiding the pointer; I would prefer not to do so:
api.h version 2
#ifndef API_H_INCLUDED
#define API_H_INCLUDED
typedef struct my_type my_type;
extern void do_something(my_type *x);
extern my_type *my_type_initializer(void);
extern void my_type_release(my_type *x);
#endif /* API_H_INCLUDED */
core.c version 2
#include "api.h"
#include <stdio.h>
#include <stdlib.h>
struct my_type
{
int a;
};
void do_something(my_type *x)
{
printf("Value: %d\n", x->a);
}
my_type *my_type_initializer(void)
{
my_type *x = malloc(sizeof(*x));
x->a = 57; // More plausibly, this would be 0
return x;
}
void my_type_release(my_type *x)
{
free(x);
}
main.c
#include "api.h"
int main(void)
{
my_type *x = my_type_initializer();
do_something(x);
my_type_release(x);
return 0;
}
That's nice and clean. Of course, the user cannot allocate a struct my_type (only a pointer to it), so you need a function to allocate the structure for them. Think of the Standard C Library, and the FILE type, and fopen() to allocate and fclose() to release and fprintf() etc to manipulate the type. The my_type_initializer() is functioning as an analogue to fopen(), my_type_release() as an analogue to fclose(), and do_something() as an analogue to fprintf().
Jonathan, you beat me to an answer, but this may be helpful as well. Here, api.c contains the (private) implementation, and api.h provides the interface to be consumed by other code such as main.c.
// main.c: uses only the public interface to the private code
#include "api.h"
int main(int argc, char *argv[]) {
void *foo;
foo = create_foo("five", 5);
print_foo(foo);
delete_foo(foo);
}
// EOF main.c
// api.h: the public interface
#ifndef _api_h_
#define _api_h_
void *create_foo(char *name, int number);
void print_foo(void *foo);
void delete_foo(void *foo);
#endif // _api_h_
// api.c: the private implementation
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// The real structure is private to the implementation.
typedef struct {
char name[20];
int number;
} real_struct;
// Create a new structure, initialize, return as ptr-to-void.
void *create_foo(char *name, int number) {
real_struct *s = malloc(sizeof(real_struct));
strcpy(s->name, name);
s->number = number;
return (void *) s;
}
// Print the data.
void print_foo(void *foo) {
real_struct *s = (real_struct *) foo;
printf("name: %s, number: %d\n", s->name, s->number);
}
// Release the memory.
void delete_foo(void *foo) {
free(foo);
}
// EOF api.c
This code should compile and run:
$ gcc -o foo main.c api.c
$ ./foo
name: five, number: 5