Skip to main content
GameDev.net gamedev.net
🔒 Locked

Problem using a structure and an enum for parameters

Started by kzar Nov 18, 2004 at 9:07 AM 13 replies 900+ views
Original Post
kzar
kzar
Having a bit of troubles with my (too?) clever function. Its giving me this error. "[Warning] Parameter has incomplete type"

typedef struct sCharacter character;
enum Estate {RIGHT, LEFT, DOWN, UP};

void set_state(character bloke, enum Estate state);

struct sCharacters {
    bool used;
	int x;
	int y;
	enum Estate state;  
	int frame_x;
	int frame_y;
	char *image;
};


nmi
nmi
In which line did you get the error ?

try:
enum Estate {RIGHT, LEFT, DOWN, UP};struct character {        bool used;	int x;	int y;	Estate state;  	int frame_x;	int frame_y;	char *image;};void set_state(character bloke, Estate state);

kzar
kzar
i get the error on the line "void set_state(character bloke, enum Estate state);"
smr
smr
Quote:
Original post by kzar
Having a bit of troubles with my (too?) clever function. Its giving me this error. "[Warning] Parameter has incomplete type"

/* vHEREv */
void set_state(struct character bloke, enum Estate state)


because you didn't typedef your struct, you need to tell the compiler that you are referencing a struct in your prototype here. In C and C++ the name of structs, enums, and unions are not considered to be datatypes by the complier. They are *tags*. So, if you try to use a tag as a datatype you get an error. You can get around this by doing a typedef:

struct point {    int x;    int y;};typdef struct point POINT;/* OR */typedef struct {    int x;    int y;} POINT;


I prefer not to typedef structs because you will run into errors when your struct needs to refer to an instance of itself. This becomes _very_ irritating with linked lists. GCC and other single-pass compilers exhibit this behaviour.

/* This won't compile on a single-pass compiler  * because it doesn't know anything about the  * NODE datatype until it reaches the very end * of the struct definition.*/typedef struct {    void *data;    NODE *previous;    NODE *next;} NODE;/* This will work */struct NODE {    void *data;    struct NODE *previous;    struct NODE *next;};


It is somewhat inconvenient to type "struct" all of the time, but you get used to it. I've seen some opt to declare everything with typedefs *except* for structs which refer to themselves, but IMO this is inconsistent. I personally chose one way that always works and use it consistantly.
Lord Bart
Lord Bart
Hello kzar,

I am not sure which compiler your use but enum Estate { };
Estate should now be a type, you don't have to use enum keyword before it.

do like nmi says.

If that doesn't work you could use typedef.

typedef enum Estate { ... } Estate/*(this is the typedef name)*/;

Might need to chage the typedef name so it dosn't conflit with enum name.

Hello smr,

you should be able to typedef link list.

typedef struct NODE/*tag name*/ {
void *data;
struct NODE *previous;
struct NODE *next;
} NODE/*typedef name*/;

the first NODE in (typedef struct NODE) is tag.
the NODE is (} NODE;) is the typedef name.

Lord Bart :)
Conner McCloud
Conner McCloud
Quote:
Original post by smr
because you didn't typedef your struct, you need to tell the compiler that you are referencing a struct in your prototype here. In C and C++ the name of structs, enums, and unions are not considered to be datatypes by the complier. They are *tags*. So, if you try to use a tag as a datatype you get an error. You can get around this by doing a typedef:

I am pretty sure this is no longer true, at least in C++. I've never used struct when defining objects, and I've never had a problems with compiling on VC++ or gcc.

CM
kzar
kzar
i fixed it. The two problems where mistyping sCharacter and putting them in the wrong order. This now works.

edit: almost forgot, thanks for the sugestions :D

enum Estate {RIGHT, LEFT, DOWN, UP};typedef struct sCharacter character;struct sCharacter {    bool used;	int x;	int y;	enum Estate state;  	int frame_x;	int frame_y;	char *image;};void set_state(character bloke, enum Estate state);
smr
smr
That last post was mine ... forgot to log in.
Sharlin
Sharlin
EDIT: Ah, too slow, too slow. Anyway, hope this post is still of use, explaining why exactly the error occured in the first place.

---

In C you need to qualify your struct, union, and enum variables with the appropriate keyword, yes (or typedef them), but in C++ you don't (for backwards compatibility, it is legal to do so but not required). The error kzar's getting, however, is caused by another reason entirely.

The problem is that when the compiler sees a function declaration (in our case, void set_state(character bloke, enum Estate state)), it needs to know the types (particularly, their sizes) of all the parameters in order to be able to call it correctly. But, in this case it doesn't have that information! It doesn't know anything about the type "character", except that it is a typedef for a struct that is defined somewhere else. Maybe just after the function declaration, maybe in another source file entirely. At that point, the compiler hasn't got any idea as to what the struct actually contains, thus the struct has an "incomplete type" and cannot be used as a parameter to a function.

The solution is to declare the function *after* the struct, as nmi did in his message.

BTW, passing a *pointer* to an incomplete type works, because all data pointers are guaranteed to have the same size, independent of the type of the pointee.
smr
smr
lol I completely overlooked that ... duh. By the time I started writing my post I forgot that he had typedefed it.
Enigma
Enigma
smr - what language are you using? The code you posted is a weird mix of C and C++. You're using C++ iostreams with the C definition of NULL and unnecessary struct qualifiers. In pure C++ that should have been:
#include <iostream>#include <conio.h>#ifndef NULL// the C++ definition of NULL is 0#define NULL 0#endifstruct NODE {    void *data;// in C++ no need to qualify with struct    NODE *prev;    NODE *next;};// don't use argc and argv, so no need to declare them.  int main() is a valid entry point in C++int main(){// in C++ no need to qualify with struct    NODE first;    NODE last;    int x = 10;    int y = 11;    int dummy;        first.data = &x    first.prev = NULL;    first.next = &last        last.data = &y    last.prev = &first    last.next = NULL;        std::cout << "First node is: " << *(int *) first.data << std::endl;    std::cout << "Last node is: " << *(int *) last.data << std::endl;    while(!getch());    return 0;}


Of course you'd probably want to use a templated NODE rather than a void*, or just use std::list.

Enigma
smr
smr
Quote:
Original post by Enigma
smr - what language are you using? The code you posted is a weird mix of C and C++. You're using C++ iostreams with the C definition of NULL and unnecessary struct qualifiers. In pure C++ that should have been:
*** Source Snippet Removed ***

Of course you'd probably want to use a templated NODE rather than a void*, or just use std::list.

Enigma


I typically use C.

I used my own definition of NULL because I wasn't sure if it was defined in iostream. I always define NULL as a void * because NULL is pointer where zero is an integer. I wouldn't assign a pointer to an integer without a cast, so I don't assign an integer to a pointer without a cast.

Me explicitly stating struct is my mistake. I almost exclusively code in C, so I am used to having to work around tag and datatype problems the C way.

int main(char argc, char **argv) is also a valid entry point. It's just habit for me.

I used NODE because I was demonstrating a point.

Thanks for pointing that stuff out btw. I'm wrapping up a project in C and plan to move back to C++ soon. I'm a little rusty.
Enigma
Enigma
Quote:
Original post by smr
I used my own definition of NULL because I wasn't sure if it was defined in iostream. I always define NULL as a void * because NULL is pointer where zero is an integer. I wouldn't assign a pointer to an integer without a cast, so I don't assign an integer to a pointer without a cast.


C++ does not allow for a void* to be converted to a typed pointer without an explicit cast, although some compilers will let you get away with it. Null is a bit of a sore-spot in C++ at the moment. I believe there are plans to add nullptr as a keyword with the next revision of the language. In the meantime, the best solution I've come across is Scott Meyers' Null class:
class Null{	public:		template <typename TYPE>		operator TYPE*() const		{			return 0;		}		template <typename TYPE, class CLASS>		operator TYPE CLASS::*() const		{			return 0;		}	private:		void operator&() const;} const null;


Enigma

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.