Error with two almost identical pieces of code - c

**I am new to C so please keep that in mind when answering
I'm currently working on a larger program where I use classes called integer.c (which defines an integer and functions used on it), real.c (which defines a double and functions used on it) and comparator.c (which defines functions used to compare these different data types (each class does have a header as well).
When I try and compile the larger program, I get an error in my comparator.c file stating:
comparator.c:25:23: error: expected expression
return ((integer *) p)->value - ((integer *) q->value);
^
comparator.c:25:14: error: use of undeclared identifier 'integer'
return ((integer *) p)->value - ((integer *) q->value);
^
comparator.c:25:48: error: expected expression
return ((integer *) p)->value - ((integer *) q->value);
^
comparator.c:25:39: error: use of undeclared identifier 'integer'
return ((integer *) p)->value - ((integer *) q->value);
^
comparator.c:23:25: warning: unused parameter 'p' [-Wunused-parameter]
int intComparator(void *p, void *q)
^
comparator.c:23:34: warning: unused parameter 'q' [-Wunused-parameter]
int intComparator(void *p, void *q)
^
Here is my comparator.c class and I want to note how my intComparator functions and realComparator functions are almost identical so I cannot see why I do not get these errors for my realComparator:
#include <stdio.h>
#include <limits.h>
#include <assert.h>
#include <string.h>
#include "comparator.h"
#include "str.h"
#include "integer.h"
#include "real.h"
//returns >0 if p is > q, returns 0 if equal, returns <0 is q is > p
int intComparator(void *p, void *q)
{
return ((integer *) p)->value - ((integer *) q)->value;
}
////returns >0 if p is > q, returns 0 if equal, returns <0 is q is > p
double realComparator(void *p,void *q)
{
return ((real *) p)->value - ((real *) q)->value;
}
int stringComparator(void *p,void *q)
{
int r = strcmp((char *)p, (char *)q);
return r;
}
Here is my integer.c class and real.c class for comparison (please note that any programming style of this program that might seem weird is because it is for a class project where I need to follow style and program outline instructions):
integer.c:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
#include "integer.h"
extern void Fatal(char *,...);
integer *
newInteger(int x)
{
integer *p = malloc(sizeof(integer));
if (p == 0)
{
fprintf(stderr,"out of memory\n");
exit(-1);
}
p->value = x;
return p;
}
int
getInteger(integer *v)
{
assert(v!=0);
return v->value;
}
void
displayInteger(FILE *fp,void *v)
{
assert(v!=0);
fprintf(fp,"%d",getInteger((integer *) v));
}
void
freeInteger(integer *v)
{
free(v);
}
real.c:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
extern void Fatal(char *,...);
real *
newReal(double x)
{
real *p = malloc(sizeof(real));
if (p == 0)
{
fprintf(stderr,"out of memory\n");
exit(-1);
}
p->value = x;
return p;
}
double
getReal(real *v)
{
assert(v!=0);
return v->value;
}
void
displayReal(FILE *fp,void *v)
{
assert(v!=0);
fprintf(fp,"%f",getReal((real *) v));
}
void
freeReal(real *v)
{
free(v);
}
and here are my integer.h and real.h files:
integer.h:
#include <stdio.h>
#ifndef __INTEGER_INCLUDED__
#define __INTEGER_INCLUDED__
typedef struct integer
{
int value;
} integer;
extern integer *newInteger(int);
extern int getInteger(integer *);
extern void displayInteger(FILE *,void *);
extern void freeInteger(integer *);
#define PINFINITY IN_MAX
#define NINFINITY IN_MIN
#endif
real.h:
#include <stdio.h>
#ifndef __REAL_INCLUDED__
#define __REAL_INCLUDED__
typedef struct real
{
double value;
} real;
extern real *newReal(double);
extern double getReal(real *);
extern void displayReal(FILE *,void *);
extern void freeReal(real *);
#define PINFINITY IN_MAX
#define NINFINITY IN_MIN
#endif
Here is str.h:
#include <stdio.h>
#ifndef __STRING_INCLUDED__
#define __STRING_INCLUDED__
extern char * getString(char *);
extern void displayString(FILE *,void *);
extern void freeString(char *);
#define PINFINITY IN_MAX
#define NINFINITY IN_MIN
#endif
and comparator.h:
#ifndef comparator_h
#define comparator_h
typedef int (*Comparator)(void*,void*);
typedef void (*Printer)(FILE*,void*);
extern int intComparator(void *p, void *q);
extern int realComparator(void *p, void *q);
extern int stringComparator(void *p, void *q);
#endif /* comparator_h */
I've been staring at this for so long and have checked everything multiple times and can't figure out why I'm getting these errors. Any help would be great, thanks.

Look closely at the parenthesis:
return ((integer *) p)->value - ((integer *) q->value);
// ^^^^^^^^^^^^^^
return ((real *) p)->value - ((real *) q)->value;
// ^^^^^^^^^^^
In the first case, you're casting q->value to integer*.
In the second case, you're casting q to real*, then accessing ->value.
I assume that the first case is an error.

I see a couple of issues, but first, I want to suggest a code modification to assist in debugging. You wrote a lot of code in one line. I suggest that you break the code into parts until you understand it. Then when it is working, you can combine it together. Like this:
int intComparator(void *p, void *q)
{
int rval;
int p1;
int q1;
p1 = (int *)p -> value;
q1 = (int *)q -> value;
rval = p1 - q1;
return (rval);
}
Now, here are two issues that I see:
1. You are attempting to cast p and q as pointers to integers. I think you need to cast them as pointers to int, not integer.
2. In realcomparator, you are returning an int but you are working with real numbers, I think. Either you should change the return value to a real, or convert the result to an integer before returning it.

Related

Error *** has no member named ***

I don't know what i'm doing wrong ..
Do you have any ideas what i'm doing wrong? Structure was declared in header file sender.h - code below
After trying to compile this program I got this error:
Sender/Sender.c: In function 'SenderCreate':
Sender/Sender.c:50: error: 'Sender' has no member named 'sim_buf'
Sender/Sender.c:51: error: 'Sender' has no member named 'sim_buf_length'
Sender/Sender.c: In function 'SenderExecuteTask':
Sender/Sender.c:75: error: 'sim_buf_length' undeclared (first use in this function)
Sender/Sender.c:75: error: (Each undeclared identifier is reported only once
Sender/Sender.c:75: error: for each function it appears in.)
Sender/Sender.c:77: error: 'sim_buf' undeclared (first use in this function)
make: *** [Sender.o] Error 1
Code of program below:
#include <stdlib.h> // calloc, free
#include <stdio.h>
#include "Sender.h"
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include "../../rdo_module/readout_dev.h"
struct Sender_s {
ET4DataSource *data_source;
unsigned int num_of_images;
unsigned int num_of_el;
ConditionWait *condition_wait;
int sock;
struct sockaddr *PC;
char *sim_buf;
char *sim_buf_length;
};
void SenderSetNumOfEl(Sender *self, unsigned int num_of_el) {
self->num_of_el = num_of_el;
}
Sender *
SenderCreate(ET4DataSource *data_source,
unsigned int num_of_images,
unsigned int num_of_el,
ConditionWait *condition_wait,
int sock,
struct sockaddr *PC,
char *sim_buf, // here I get some problems
int *sim_buf_length) // and here
{
#ifdef DEBUG
printf("Sender.c SenderCreate line 25: Sender *self = calloc(1, sizeof(Sender));\n");
#endif
Sender *self = calloc(1, sizeof(Sender));
#ifdef DEBUG
printf("Sender.c SenderCreate line 25: success\n");
#endif
self->data_source = data_source;
self->num_of_images = num_of_images;
self->num_of_el = num_of_el;
self->condition_wait = condition_wait;
self->sock = sock;
self->PC = PC;
self->sim_buf = sim_buf;
self->sim_buf_length = sim_buf_length;
return self;
}
void
SenderDestroy(Sender *self)
{
free(self);
}
void *
SenderExecuteTask(void *self_)
{
Sender *self = self_;
ET4Buffer *buf = NULL;
int n = 0;
int c_len = sizeof(*(self->PC));
while(1) {
if(*sim_buf_length) {
n=sendto(self->sock, sim_buf, *sim_buf_length, 0, self->PC, c_len);
if(n < 0) {
perror("error in sendto()");
return NULL;
}
}
return NULL;
}
Code of sender.h below:
#ifndef __SENDER_H__
#define __SENDER_H__
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include "../Utils/ConditionWait.h"
#include "../DataSource/ET4DataSource.h"
typedef struct Sender_s Sender;
Sender *
SenderCreate(ET4DataSource *data_source,
unsigned int num_of_images,
unsigned int num_of_el,
ConditionWait *condition_wait,
int sock,
struct sockaddr *PC,
char *sim_buf,
int *sim_buf_length);
void
SenderDestroy(Sender*self);
void *
SenderExecuteTask(void *self_);
void SenderSetNumOfEl(Sender *self, unsigned int num_of_el);
#endif /*__SENDER_MAKER_H__*/
The error messages and the source in the question don't match!
When I take the source given, the compiler tells, what is wrong.
There is no member sim_buf_length, (note it does not complain about sim_buf_length_flag)
I don't get the error message "error: ‘Sender’ has no member named ‘sim_buf’", because the member is clearly present
Furthermore the types char* (Sender_s member) and int* (SenderCreate argument) don't match
The error messages for function SenderExecuteTask are clear, there are no variables declared sim_buf or sim_buf_length(_flag). Probably the function signature should have been
void *SenderExecuteTask(Sender *self);
and then in the definition self->sim_buf and self->sim_buf_length(_flag) used respectively.

function pointer not working for int

Im trying to use the power of function pointers, it all went fine until i tried to make the function pointer use a 2nd argument as type int.
The code below generates an error, which is displayed below
In an header file:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct UnitTag {
int x;
int y;
void (*move)(Unit, int);
} Unit;
Error:
error: expected ‘)’ before ‘int’
void (*move)(Unit, int);
^
void (*move)(Unit); works all fine, which surprises me how adding an argument can cause an error.
I call my struct in a C file, by including header and then doing:
Unit units[UNITCOUNT];
units[0].move(&units[0], 1);
Update:
adding:
typedef struct UnitTag Unit
Causes the error to dissapear, however I can no longer use the function as before.
error: incompatible type for argument 1 of ‘units[i].move’
units[0].move(&units[0], 0);
^
note: expected ‘Unit’ but argument is of type ‘struct UnitTag *’
If I'm getting you, you can simply use struct keyword:
#include <stdio.h>
typedef struct UnitTag {
int x;
int y;
void (*move)(struct UnitTag, int);
} Unit;
void Test (struct UnitTag test1, int test2)
{
printf("Test1.x: %d\n", test1.x);
printf("Test1.y: %d\n", test1.y);
printf("Test2 : %d\n", test2);
}
int main(void)
{
Unit units[100];
units[0].move = Test;
units[0].x = 1;
units[0].y = 2;
units[0].move(units[0], 3);
}
Output:
Test1.x: 1
Test1.y: 2
Test2 : 3
If you want to pass struct by referebce, simply:
#include <stdio.h>
typedef struct UnitTag {
int x;
int y;
void (*move)(struct UnitTag*, int);
} Unit;
void Test (struct UnitTag *test1, int test2)
{
test1->x = 4;
test1->y = 5;
}
int main(void)
{
Unit units[100];
units[0].move = Test;
units[0].x = 1;
units[0].y = 2;
units[0].move(&units[0], 3);
printf("units[0].x: %d\n", units[0].x);
printf("units[0].y: %d\n", units[0].y);
}
Output is:
units[0].x: 4
units[0].y: 5
You need the prototype for Unit before using it.
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct UnitTag Unit;
typedef struct UnitTag {
int x;
int y;
void (*move)(Unit, int);
} Unit;
int main(void)
{
return 0;
}
After the clarification what you wanted to do. It probably makes more sense to give a pointer to Unit, so that the move command which returns void can change something about your object.
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct UnitTag Unit;
typedef struct UnitTag {
int x;
int y;
void (*move)(Unit *, int);
} Unit;
Unit test;
/* some function that corresponds to the interface */
void myMove(Unit *u, int i)
{
u->x = u->x + i;
}
int main(void)
{
/* initialize test struct */
test.x = 0;
test.y = 0;
test.move = myMove;
test.move(&test, 5);
printf("Values after move are (x, y) = (%i, %i).\n", test.x, test.y);
return 0;
}

Understanding OOPC, am I doing it right?

I followed Alex's book on object oriented programming using ansi c.
So far tried to model a very basic string class -
Here's the code:
main.c
#include <stdio.h>
#include <stdlib.h>
#include "class.h"
#include "mystring.h"
extern const void *String_c;
int main() {
String *my = new(String_c, "A random string");
char *text = my->str(my);
printf("String contains %s of length %d", text, my->length(my));
delete(my);
free(text);
return 0;
}
class.h
#ifndef CLASS_H_
#define CLASS_H_
#include <stddef.h>
typedef struct {
size_t size;
void* (*ctor) (void* self, va_list *app);
void (*dtor) (void* self);
} Class;
void* new(const void *class, ...);
void delete(void *object);
#endif /* CLASS_H_ */
class.c
/*
* class.c
*
* Created on: 22-Mar-2014
* Author: nilesh
*/
#include <stdarg.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include "class.h"
void *new(const void *_class, ...) {
printf("\nCreating new\n");
const Class *class = _class;
void *p = calloc(1, class->size);
assert(p);
* (const Class **) p = class;
if(class->ctor) {
va_list ap;
va_start(ap, _class);
p = class->ctor(p, &ap);
va_end(ap);
}
return p;
}
void delete(void *object) {
printf("\nDelete\n");
const Class **class = object;
if(object && *class && (*class)->dtor)
(*class)->dtor(object);
free(object);
object = NULL;
}
mystring.h
#ifndef STRING_H_
#define STRING_H_
#include <stddef.h>
#include "class.h"
typedef struct string String;
struct _string;
struct string {
const Class *class;
struct _string *_;
int (*length) (String *self);
char* (*str) (String *self);
};
extern Class _string_class;
extern const void *String_c;
#endif /* STRING_H_ */
mystring.c
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "mystring.h"
struct _string {
char *data;
int length;
};
static int length(String *self) {
return self->_->length;
}
static char* str(String *self) {
char *ret = malloc(sizeof(char) * self->_->length);
memcpy(ret, self->_->data, sizeof(char)*self->_->length);
return ret;
}
void* ctor(void *_self, va_list *app) {
printf("\nConstructor called\n");
String *self = _self;
self->_ = malloc(sizeof(struct _string));
char *text = va_arg(*app, char *);
self->_->length = strlen(text);
self->_->data = malloc(sizeof(char) * self->_->length);
memcpy(self->_->data, text, sizeof(char) * self->_->length);
self->length = length;
self->str = str;
return self;
}
void dtor(void *_self) {
printf("\nDestructor called\n");
String *self = _self;
free(self->_);
free(self->_->data);
self->_->data = NULL;
}
Class _string_class = {sizeof(String), ctor, dtor};
const void *String_c = &_string_class;
I have one question:
Why does
Class *class = object
In delete not work, while
Class **class = object
Works?
Works in the sense, in former it doesn't call dtor, but calls length and in case of latter, the call to function is (*class)->dtor which works.
The short answer is that class is of type Class **; class->dtor would work only if class were of type Class *.
You're probably getting confused because of the double indirection, so here's a longer explanation:
Think about structures layout. Imagine you have a simple structure like so:
struct example {
int xpto;
char a[10];
}
If you call a function f() and pass it a pointer p to struct example, then f() is free to cast such a pointer to int *. Dereferencing such a pointer yields the same result as p->xpto. That is, p->xpto and *(int *) p are equivalent. This happens because structure components are layed out in increasing memory addresses. xpto is the first member, meaning it's at offset 0. In other words, for any pointer to struct example, the first sizeof(int) bytes at the address pointed to by p belong to xpto.
Your string structure was defined as:
struct string {
const Class *class;
struct _string *_;
int (*length) (String *self);
char* (*str) (String *self);
};
Which shows that at offset 0 of struct string there is a (read-only) pointer to Class. When you call delete(my) in main(), you are giving it a pointer to struct string - thus, the first sizeof(const Class *) bytes in the address pointed to by my are a pointer to a Class. Like we did in the example with struct example - where we casted p to a pointer to the first member - casting such a pointer to Class ** (first member is a Class *, so a pointer to the first member is of type Class **) gives direct access to the first field (and only the first).
Because of that, delete() casts the pointer you give it to a Class **, because by doing so, dereferencing such a pointer yields a Class *.
Why doesn't class->dtor() work? Because class is of type Class **, so, class->dtor, which is equivalent to (*class).dtor is invalid: *class is of type Class *, it's not a structure, and as such, there is no member named dtor. You must use (*class)->dtor, since that's the same as (*(*class)).dtor.

Void-pointers in generic stack implementation (Plain C)

I'm trying to make a generic stack in plain C and I have some problems with pointers and no idea where is the problem.
Here's the structure and functions, where I have problems:
typedef struct{
void *elems;
int elemSize;
int logLength;
int allocLength;
} genStack;
void GenStackPush(genStack *s, const void *elemAddr);
void GenStackPop(genStack *s, void *elemAddr);
That's the implementation:
void GenStackPush(genStack *s, const void *elemAddr)
{
s->elems[s->logLength] = elemAddr;
s->logLength++;
}
void GenStackPop(genStack *s, void *elemAddr)
{
s->logLength--;
elemAddr = s->elems[s->logLength];
}
The usage should look like this:
int val;
genStack IntegerStack;
for (val = 0; val < 6; val++)
GenStackPush(&IntegerStack, &val);
GenStackPop(&IntegerStack, &val);
printf("Popped: %d\n",val);
And here are the problems I get:
genstacklib.c: In function ‘GenStackPush’:
genstacklib.c:60:10: warning: dereferencing ‘void *’ pointer [enabled by default]
genstacklib.c:60:2: error: invalid use of void expression
genstacklib.c: In function ‘GenStackPop’:
genstacklib.c:72:23: warning: dereferencing ‘void *’ pointer [enabled by default]
genstacklib.c:72:13: error: void value not ignored as it ought to be
I have tried already several ways to fix the code, but none of them worked.
Thanks.
==========================================================================
So, guys, thanks for help! Now it compiles, but I have changed an API, which was given by our Professor. There was also the problem with 'const' qualifier, so I deleted them. Not my code looks like this:
genstacklib.h:
#ifndef GENSTACKLIB_H
#define GENSTACKLIB_H
#define GenStackInitialAlocationSize 4
typedef struct{
void** elems;
int elemSize;
int logLength;
int allocLength;
}genStack;
void GenStackNew(genStack *s,int elemSize);
void GenStackDispose(genStack *s);
int GenStackEmpty(const genStack *s);
void GenStackPush(genStack *s, void *elemAddr);
void GenStackPop(genStack *s, void *elemAddr);
#endif
genstacklib.c:
#include <stdlib.h>
#include <stdio.h>
#include "genstacklib.h"
void GenStackNew(genStack *s,int elemSize)
{
void** newElems;
/* Allocate a new array to hold the contents. */
newElems = (void**) malloc(elemSize * GenStackInitialAlocationSize);
if (newElems == NULL)
{
fprintf(stderr, "Error with allocating the stack.\n");
exit(1); /* Exit, returning error code. */
}
s->elems = newElems;
s->allocLength = GenStackInitialAlocationSize;
s->logLength = 0; /*is empty*/
}
void GenStackDispose(genStack *s)
{
s->allocLength = 0;
free(s->elems);
}
int GenStackEmpty(const genStack *s)
{
return s->logLength == 0;
}
void GenStackPush(genStack *s, void *elemAddr)
{
s->elems[s->logLength] = elemAddr;
s->logLength++;
}
void GenStackPop(genStack *s, void *elemAddr)
{
s->logLength--;
elemAddr = s->elems[s->logLength];
}
If you have any ideas to improve it or something to say about it, I would hear with pleasure. :D
you are trying to dereference void pointer without typecasting to some other type which causing the problem.
elems has the wrong type. If you declare it as void* the compiler does not know how big the things it points to are. So it can't do pointer arithmetic or array subscripting on it or even dereference what it points to.
Conceptually elems is an array of the things that you put on the stack. What do you put on the stack? Pointers - declared as void*. So elems should be an array of void* objects. You can declare it like this
typedef struct{
void *elems[STACK_SIZE];
int elemSize;
int logLength;
int allocLength;
} genStack;
which will reserve space in the struct for the array (making the struct itself very big), or you can declare it as a pointer to void* i.e. void**
typedef struct{
void **elems;
int elemSize;
int logLength;
int allocLength;
} genStack;
If you go for this option, you then have to manually allocate the memory
genStack* genStackAlloc()
{
genStack* ret = calloc(1, sizeof *ret);
ret->elemns = calloc(STACK_SIZE, sizeof(void*));
// rest of the initialisation
return ret;
}
And of course, you'll have to manually free the memory when you dispose of the stack.
elems is declared as a pointer to a void, where I think you want it to be a pointer to a void*.
The problem is s->elems[s->logLength] :
First, the member variable void *elems use to store the element address (void *), array of the element (void ), so the type of the elems should be (void *), and you should allocate the memory to store the address.
You can allocate memory by the following ways:
void * elems[MAX_STACK_SIZE];
OR
void ** elems
s->elems = (void**)malloc(MAX_STACK_SIZE*sizeof(void*)); // and allocate it before use it.

Typecasting (or deference) void * to struct foo*

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

Resources