previous declaration of Table was here / conflicting types for

M

Michael.Z

Anyone who can help:

Given a Table.h file I am writing a Table.c file.
I keep getting the compile error:

previous declaration of Table was here / conflicting types for


I think the problem was the result of two pieces of code.
First: typedef struct Table; /* in Table.c*/
Second: struct Table { /*struct definition */ } *Table; /* in
Table.h */

How can I solve the problems?



Here are the two files


/* * * * * * * * * * * * * * * * * * * * * * *
Header file:
* * * * * * * * * * * * * * * * * * * * * * */


#ifndef TABLE_H
#define TABLE_H


#include "bool.h"

typedef void * Table ;
typedef void * DataT ;

typedef struct {
// unsigned successful ; double unsuccessful ;
unsigned successfulNumerator , successfulDenominator ;
unsigned unsuccessfulNumerator , unsuccessfulDenominator ;
} Perform ;

Table
makeTable ( int sizeTable , unsigned sizeData , int (*diff)() ,
unsigned (*hash)() , void * (*copy)() , void (*free)() ) ;


#endif



/* * * * * * * * * * * * * * * * * * * * * * *
Table.c
* * * * * * * * * * * * * * * * * * * * * * */

#include "Table.h"


typedef struct Table{
int sizeTable;
unsigned sizeData;
int (*diff)();
unsigned (*hash)();
void *(*copy)();
void (*free)();
} * Table;

Table
makeTable ( int sizeTable , unsigned sizeData , int (*diff)() ,
unsigned (*hash)() , void * (*copy)() , void (*free)() ) {
}
 
F

Flash Gordon

Michael.Z wrote, On 03/05/08 08:22:
Anyone who can help:

Given a Table.h file I am writing a Table.c file.
I keep getting the compile error:

previous declaration of Table was here / conflicting types for


I think the problem was the result of two pieces of code.
First: typedef struct Table; /* in Table.c*/

This says that Table is a struct.
Second: struct Table { /*struct definition */ } *Table; /* in
Table.h */

This says it is a pointer to a struct, that is what the * means.
How can I solve the problems?

By not providing different definitions.
Here are the two files

typedef void * Table ;

This is not what you said you had and is defining table as yet another type.

typedef struct Table{
int sizeTable;
unsigned sizeData;
int (*diff)();
unsigned (*hash)();
void *(*copy)();
void (*free)();
} * Table;


This is what you said. However pointers to void and pointers to structs
are different things for the simple reason that void and struct are
different.

Also hiding pointers behind a typedef is generally considered a bad thing.
 
A

ade ishs

Michael.Z said:
Anyone who can help:

Given a Table.h file I am writing a Table.c file.
I keep getting the compile error:

previous declaration of Table was here / conflicting types for
#ifndef TABLE_H
#define TABLE_H

#include "bool.h"

typedef void * Table ;

You have it here, ...

[snip]
/* * * * * * * * * * * * * * * * * * * * * * *
Table.c
* * * * * * * * * * * * * * * * * * * * * * */

#include "Table.h"


typedef struct Table{
int sizeTable;
unsigned sizeData;
int (*diff)();
unsigned (*hash)();
void *(*copy)();
void (*free)();
} * Table;

And you also have it here.

In Table.h, you make Table a typedef of void *, and in Table.c, you make
Table a typedef of struct Table { ... } *.
 
M

Michael.Z

Hi Flash Gordon:

Thanks for your reply.
The Table.c was required to be implemented as generic type. If I am
right, Table is declared as void * in header file, the reason is that,
when used later on, it can be casted to any other type of pointers.

The implementation of Table in Table.c was defined as pointer to
struct Table, because I need to implement the members of Table.

My professor told us, void * in header indicates a generic type.
He has some sample codes where List was typedef'd void pointer but the
definition was struct List Pointer:

/* Header file List.h*/
#ifndef LIST_H
#define LIST_H

#include "bool.h"

typedef void * List ;
typedef void * DataL ;
typedef void * ListIt ;

List makeList ( int , void * (*copy)() , void (*free)() ) ;
void freeList ( List ) ;
void clearList ( List ) ;

boolean accessList ( List , DataL , int ) ;
int lengthList ( List ) ;

boolean accessHead ( List , DataL ) ;
boolean insertHead ( List , DataL ) ;
boolean deleteHead ( List , DataL ) ;

/* not all the header file is copied here*/









/* List.c */

#include "bool.h"
#include <stdio.h>
#include <stdlib.h>

#ifndef DATA
#define DATA
typedef void * Data ;
#endif

typedef struct ListNode {
struct ListNode * next ; /* reference to following ListNode */
struct ListNode * previous ; /* reference to preceding ListNode */
Data dptr ;
} ListNode ;

typedef struct List {
ListNode * head ; /* Head end of List */
ListNode * tail ; /* Tail end of List */
int _lengthList ; /* number of items within List */
int _sizeData ; /* byte size of data to be stored */
void (*_freeData)( ) ; /* returns data item to heap */
void * (*_copyData)( ) ; /* copies data item to another */
} * List ;


Regards
Michael
 
N

Nick Keighley

Hi Flash Gordon:
The Table.c was required to be implemented as generic type.

I'm not sure what a "generic type" is and I have been programming
for quite a while.
 If I am
right, Table is declared as void * in header file, the reason is that,
when used later on, it can be casted to any other type of pointers.

It may be you trying to hide implementation details from users
of your code. The outside world uses a void* and your
code (the library) casts it to the right type before use.
This is good. The internal data structure can change
without causing a recompile of the user code.

/* pippo.h */
typedef void* Table_handle;
Table_handle create();
void befunge (Table_handle);

/* pippo.c */
void befunge (Table_handle handle)
{
Table* table = (Table*)handle;
...
}

/* user.c */
int main (void)
{
Table_handle* my_table;
my_table = create();
befunge(my_table);
return 0;
}

The point is I *don't* try and have two differing
definitions of Table.

The implementation of Table in Table.c was defined as pointer to
struct Table, because I need to implement the members of Table.

My professor told us, void * in header indicates a generic type.
He has some sample codes where List was typedef'd void pointer but the
definition was struct List Pointer:

so he had two different types didn't he?

/* Header file List.h*/
#ifndef LIST_H
#define LIST_H

#include "bool.h"

        typedef void * List ;
        typedef void * DataL ;
        typedef void * ListIt ;

        List makeList ( int , void * (*copy)() , void (*free)() ) ;
        void freeList ( List ) ;
        void clearList ( List ) ;

        boolean accessList ( List , DataL , int ) ;
        int lengthList ( List ) ;

        boolean accessHead ( List , DataL ) ;
        boolean insertHead ( List , DataL ) ;
        boolean deleteHead ( List , DataL ) ;

     /* not all the header file is copied here*/

/* List.c */

#include "bool.h"
#include <stdio.h>
#include <stdlib.h>

#ifndef DATA
#define DATA
typedef void * Data ;
#endif

typedef struct ListNode {
        struct ListNode * next ;        /* reference to following ListNode */
        struct ListNode * previous ;    /* reference to preceding ListNode */
        Data dptr ;

} ListNode ;

typedef struct List {
        ListNode * head ;               /* Head end of List             */
        ListNode * tail ;               /* Tail end of List             */
        int _lengthList ;               /* number of items within List  */
        int _sizeData ;                 /* byte size of data to be stored */
        void (*_freeData)( ) ;          /* returns data item to heap    */
        void * (*_copyData)( ) ;        /* copies data item to another  */

} * List ;

arg!!!

don't top post. Please put your reply after the text you are
replying to.


don't quote sigs (the bit after the "-- ")
 
B

Ben Bacarisse

Michael.Z said:
The Table.c was required to be implemented as generic type. If I am
right, Table is declared as void * in header file, the reason is that,
when used later on, it can be casted to any other type of pointers.

The implementation of Table in Table.c was defined as pointer to
struct Table, because I need to implement the members of Table.

My professor told us, void * in header indicates a generic type.
He has some sample codes where List was typedef'd void pointer but the
definition was struct List Pointer:

First, the more common way to "hide the implementation" is simply to
declare your functions as using a 'struct Table *' (as has already
been explained by Flash Gordon).

Secondly, this does not stop you writing generic functions that have a
'void *' parameter. You can pass a 'struct Table *' where a 'void *'
is expected when is important to do so.

There is no obvious advantage to making the Table generic (in that
sense) rather than simply hidden. In fact there is a positive
*disadvantage* to doing that -- you loose all the type-checking. It
is usually much better to stick with hidden (incomplete) struct
pointers right up to the point where you are *forced* to start using
'void *'.

Your professor may have a reason for doing this, but it does seem like
a wise choice from the sample you posted.
 
M

Michael.Z

I'm not sure what a "generic type" is and I have been programming
for quite a while.


It may be you trying to hide implementation details from users
of your code. The outside world uses a void* and your
code (the library) casts it to the right type before use.
This is good. The internal data structure can change
without causing a recompile of the user code.

/* pippo.h */typedefvoid* Table_handle;
Table_handle create();
void befunge (Table_handle);

/* pippo.c */
void befunge (Table_handle handle)
{
Table* table = (Table*)handle;
...

}

/* user.c */
int main (void)
{
Table_handle* my_table;
my_table = create();
befunge(my_table);
return 0;

}

The point is I *don't* try and have two differing
definitions of Table.



so he had two different types didn't he?

















arg!!!

don't top post. Please put your reply after the text you are
replying to.




don't quote sigs (the bit after the "-- ")

Hi Nick,

Thanks so much for your reply and your advice for not top posting and
not quote signature, I am new to this, let me know if I need more
further improvements.

Regarding to your post:
so he had two different types didn't he?

He did have two different types. Its "void *" in header file while
"struct List *" in List.c;
eg.
/*List.h*/
typedef void *List;

/*List.c*/
typedef struct List{....} *List;

However there was no conflicting type error, the reason is he did not
include file "List.h" in his "List.c".

So I removed #include "Table.h" from my "Table.c", it complied well.
Regards.
Michel Zhang
 
F

Flash Gordon

Michael.Z wrote, On 07/05/08 09:05:
On May 6, 1:21 am, Nick Keighley <[email protected]>
wrote:

Regarding to your post:

He did have two different types. Its "void *" in header file while
"struct List *" in List.c;
eg.
/*List.h*/
typedef void *List;

/*List.c*/
typedef struct List{....} *List;

In that case what he provided was wrong. No ifs, not buts, it is just
plain wrong. Wrong as in the definition of the language says that it is
wrong.
However there was no conflicting type error,

The error is still there, it is just hidden from the compiler so that it
does not tell you about it. It is no more correct than driver the wrong
way up a one way street at 100mph is legal if you do not get caught. Not
being caught does not make it legal.
the reason is he did not
include file "List.h" in his "List.c".

That, whilst not forbidden by the language, is generally considered to
be bad practice. The reason it is considered to be bad practice is
specifically *because* it hides errors like this.
So I removed #include "Table.h" from my "Table.c", it complied well.

Compiling does not make it correct. If you have a good relationship with
your tutor/lecturer/teacher you should explain to your lecturer that his
code is wrong. If your relationship is not good enough to get away with
that you should ask him why it fails to compile if the header file is
not included (but avoid arguing the point if it will affect your
grades). In either case, you should take any code presented with at
least a pinch of salt, and if he does not understand the problem you
should take the entire course with a whole keg of salt as what you are
being taught is wrong.
 
M

Michael.Zhang

Michael.Z said:
The Table.c was required to be implemented as generic type. If I am
right, Table is declared as void * in header file, the reason is that,
when used later on, it can be casted to any other type of pointers.
The implementation of Table in Table.c was defined as pointer to
struct Table, because I need to implement the members of Table. ]
My professor told us, void * in header indicates a generic type.
He has some sample codes where List wastypedef'd void pointer but the
definition was struct List Pointer:

First, the more common way to "hide the implementation" is simply to
declare your functions as using a 'struct Table *' (as has already
been explained by Flash Gordon).

Secondly, this does not stop you writing generic functions that have a
'void *' parameter. You can pass a 'struct Table *' where a 'void *'
is expected when is important to do so.

I just want to make sure I got you right.You are suggesting:
typedef struct Table{ ...} Table;
Table * makeTable( void* size, void * data);
There is no obvious advantage to making the Table generic (in that
sense) rather than simply hidden. In fact there is a positive
*disadvantage* to doing that -- you loose all the type-checking. It

I don't quit understand this part.
"generic(in that sense)": refers to what I said about my professors
way.
vs
"simply hidden": the above example. Table * makeTable( void* size,
void * data);
is usually much better to stick with hidden (incomplete) struct
pointers right up to the point where you are *forced* to start using
'void *'.


an example of being *forced* would be:

void useTable(*void myTable){
Table * makeTable = (Table *)myTable;

}

if my example is not right, any chance you can give me correct one?


Your professor may have a reason for doing this, but it does seem like
a wise choice from the sample you posted.

"
 
B

Ben Bacarisse

Michael.Zhang said:
Michael.Z said:
The Table.c was required to be implemented as generic type. If I am
right, Table is declared as void * in header file, the reason is that,
when used later on, it can be casted to any other type of pointers.
The implementation of Table in Table.c was defined as pointer to
struct Table, because I need to implement the members of Table. ]
My professor told us, void * in header indicates a generic type.
He has some sample codes where List wastypedef'd void pointer but the
definition was struct List Pointer:

First, the more common way to "hide the implementation" is simply to
declare your functions as using a 'struct Table *' (as has already
been explained by Flash Gordon).

Secondly, this does not stop you writing generic functions that have a
'void *' parameter. You can pass a 'struct Table *' where a 'void *'
is expected when is important to do so.

I just want to make sure I got you right.You are suggesting:
typedef struct Table{ ...} Table;
Table * makeTable( void* size, void * data);

Why would a parameter called size be a void *? That is possible, but
I can't say that that is what I was suggesting.

The function makeTable does sound very generic so it is not a good
example. Let's say we have a linked list. To make it generic we
could insist that items to be added are passed as void *:

List *listAdd(List *l, void *item);

We can add a table to a list like this:

List *my_list = makeList(...);
Table *tp = makeTable(...);
...
my_list = listAdd(my_list, tp);

We can insert a list into another list:

List *other = ...;
...
my_list = listAdd(my_list, other);

with not a cast in sight.
I don't quit understand this part.
"generic(in that sense)": refers to what I said about my professors
way.
vs
"simply hidden": the above example. Table * makeTable( void* size,
void * data);

That is right. Hiding the details of a struct is a very common and
important technique in C, but doing that by making it look like the
function return a void * is wrong.

From what I've seen so far your teacher's method is just plain wrong.
As a (now ex-) teacher myself, I am loath to be dogmatic -- maybe you
are being asked to write non-portable code for some very specific
reason, but declaring a function to return void * in one place and
defining it to return a Table * in another is undefined behaviour and
will break on some systems.
an example of being *forced* would be:

void useTable(*void myTable){
Table * makeTable = (Table *)myTable;

}

if my example is not right, any chance you can give me correct one?

I can't follow that at all. First,did you mean:

void useTable(void *myTable) {
Table * makeTable = (Table *)myTable;

}

If, so the cast is not needed. But anyway, why would you not know the
type of the parameter to a function called useTable? It sounds like
it will always be passed a Table *.

You are forced to use void * when you don't know the type. See
the example about of a generic list. Anything can be added to it
because the item to be added is simply a void *.
 
C

Chris Torek

Michael.Zhang said:
I just want to make sure I got you right.You are suggesting:
typedef struct Table{ ...} Table;
Table * makeTable( void* size, void * data);

I can only speak for myself, not for Ben Bacarisse, but I rather
doubt that is what he is suggesting.

In the absence of additional details, here is how *I* might do
this. Note that I prefer not to use "typedef" -- which does not
actually define types -- at all, but there are some "pro-typedef"
reasons. See <http://web.torek.net/torek/c/types2.html> for
details on this.

In this particular case, I might have a "table.h" file. In table.h,
one would find, e.g., the following (assuming the table is indexed
by simple "row,column" integer-pairs):

struct table;

struct table *table_create(void);
void *table_lookup(struct table *table, int row, int col);
int table_insert(struct table *table, int row, int col, void *data);
void *table_delete(struct table *table, int row, int col);
void table_iterate(struct table *table, void *aux,
void (*iter)(struct table *table, void *aux,
int row, int col, void *data));
void table_destroy(struct table *table, int free_all_data);

Note that there is no "{" after "struct table". This means that
the entire contents of a "struct table" are hidden. So where are
they? The answer is: in table.c (or perhaps in table-impl.h, which
is then #include-ed by table1.c and table2.c, if for some reason
"table.c" is not suitable to be used as a single file).

"Table clients", as it were, now have no idea what is *inside* a
table. They only know that they can "create" one, do "lookup"
operations, do "insert" operations, do "delete" operations, ask to
"iterate" a function (of their choosing) over all table entries,
and "destroy" a table (with, in this case, optional automatic calls
to free() on each table item, so that they need not write a "freeing
iterator").

There is still quite a bit exposed here. For instance, this makes
it clear that tables are indexed exclusively by integral (row,column)
pairs. We must also decide whether "iterate" is called for "empty"
entries (e.g., if there is a row 7, but only a column 3 in row 7
-- even though other rows have columns 0 through 5 -- does the
user's iterator get called with NULL entries for columns 0, 1, 2,
4, and 5 on row 7?). Nonetheless, the actual details of how the
tables are implemented are safely tucked away: clients know only
as much about tables as you choose to expose, while the "table
server" code (in table.c) sees all the details.

(Also, rather than "table", the above should probably called a
"sparse matrix" anyway. "Tables" might actually instead be hash
tables that implement what one uses associative arrays for in
languages like awk, for instance.)
 
M

Michael.Zhang

[snip:
[in a reply to Ben Bacarisse]
I just want to make sure I got you right.You are suggesting:
typedef struct Table{ ...} Table;
Table * makeTable( void* size, void * data);

I can only speak for myself, not for Ben Bacarisse, but I rather
doubt that is what he is suggesting.

In the absence of additional details, here is how *I* might do
this.  Note that I prefer not to use "typedef" -- which does not
actually define types -- at all, but there are some "pro-typedef"
reasons.  See <http://web.torek.net/torek/c/types2.html> for
details on this.

In this particular case, I might have a "table.h" file.  In table.h,
one would find, e.g., the following (assuming the table is indexed
by simple "row,column" integer-pairs):

    struct table;

    struct table *table_create(void);
    void *table_lookup(struct table *table, int row, int col);
    int table_insert(struct table *table, int row, int col, void *data);
    void *table_delete(struct table *table, int row, int col);
    void table_iterate(struct table *table, void *aux,
        void (*iter)(struct table *table, void *aux,
                     int row, int col, void *data));
    void table_destroy(struct table *table, int free_all_data);

Note that there is no "{" after "struct table".  This means that
the entire contents of a "struct table" are hidden.  So where are
they?  The answer is: in table.c (or perhaps in table-impl.h, which
is then #include-ed by table1.c and table2.c, if for some reason
"table.c" is not suitable to be used as a single file).

"Table clients", as it were, now have no idea what is *inside* a
table.  They only know that they can "create" one, do "lookup"
operations, do "insert" operations, do "delete" operations, ask to
"iterate" a function (of their choosing) over all table entries,
and "destroy" a table (with, in this case, optional automatic calls
to free() on each table item, so that they need not write a "freeing
iterator").

There is still quite a bit exposed here.  For instance, this makes
it clear that tables are indexed exclusively by integral (row,column)
pairs.  We must also decide whether "iterate" is called for "empty"
entries (e.g., if there is a row 7, but only a column 3 in row 7
-- even though other rows have columns 0 through 5 -- does the
user's iterator get called with NULL entries for columns 0, 1, 2,
4, and 5 on row 7?).  Nonetheless, the actual details of how the
tables are implemented are safely tucked away: clients know only
as much about tables as you choose to expose, while the "table
server" code (in table.c) sees all the details.

(Also, rather than "table", the above should probably called a
"sparse matrix" anyway.  "Tables" might actually instead be hash
tables that implement what one uses associative arrays for in
languages like awk, for instance.)

]


OFF TOPIC to previous discussion,reason being don't know where I
should post this question.

Thanks very much for all your replies. Seems most of you have a lot of
experiences in computer science. I might just ask you some questions
that I couldn't get advice from.

my problem is that I love computer science,i know how do study,but I
dont understand the material well enough, I am terrible computer
science student, I don't know what's gonna happen to person like me
after graduating with a GPA around C in CS.

I love computer science, cos I like programming, I enjoy debugging,
tracing down the logic and fix the bug. I am fancinated by the
algorithms being tought and problem solving skills I gained.
but, I am not doing well at all in my courses. My peer can finish a
programming assignment within 3 or 4 hours without help from TA at
all; while I can't progress much without help from others, it might
take me well over 20 hours even with help from others. I am not
efficient at programming at all.

Right now, I am taking a data structure and an algorithm course(Graph
theory,divide and conquer,danamic programming). I might barely pass my
data structure course, but fail the algorithm.

Before adding CS as another major, I studied some business courses
from accoutning and information systems,I did pretty well in thoese
courses,I believe I have a good study habbit.Lately, I have to admit
that I have to be a lot smarter to study Computer Science and I am not
at that level. I am sitting on the fence and don't know if I should
continue with CS(have taken 8 CS courses) or drop out of this major.

Any advice or opinion would be greatly appreciated.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top