undefined C struct forward declaration

41,096

Solution 1

Unfortunately, the compiler needs to know the size of port_t (in bytes) while compiling main.c, so you need the full type definition in the header file.

Solution 2

If you want to hide the internal data of the port_t structure you can use a technique like how the standard library handles FILE objects. Client code only deals with FILE* items, so they do not need (indeed, then generally can't) have any knowlege of what is actually in the FILE structure. The drawback to this method is that the client code can't simply declare a variable to be of that type - they can only have pointers to it, so the object needs to be created and destroyed using some API, and all uses of the object have to be through some API.

The advantage to this is that you have a nice clean interface to how port_t objects must be used, and lets you keep private things private (non-private things need getter/setter functions for the client to access them).

Just like how FILE I/O is handled in the C library.

Solution 3

A common solution that I use:

/* port.h */
typedef struct port_t *port_p;

/* port.c */
#include "port.h"
struct port_t
{
    unsigned int port_id;
    char name;
};

You use the port_p in function interfaces. You will need to create special malloc (and free) wrappers in port.h as well:

port_p portAlloc(/*perhaps some initialisation args */);
portFree(port_p);
Share:
41,096
ant2009
Author by

ant2009

Updated on July 09, 2022

Comments

  • ant2009
    ant2009 almost 2 years

    I have a header file port.h, port.c, and my main.c

    I get the following error: 'ports' uses undefined struct 'port_t'

    I thought as I have declared the struct in my .h file and having the actual structure in the .c file was ok.

    I need to have the forward declaration as I want to hide some data in my port.c file.

    In my port.h I have the following:

    /* port.h */
    struct port_t;
    

    port.c:

    /* port.c */
    #include "port.h"
    struct port_t
    {
        unsigned int port_id;
        char name;
    };
    

    main.c:

    /* main.c */
    #include <stdio.h>
    #include "port.h"
    
    int main(void)
    {
    struct port_t ports;
    
    return 0;
    }
    

    Many thanks for any suggestions,

  • Jason
    Jason about 15 years
    @litb: what do you mean? I believe in c++, main.cpp would still need a full definition of port_t in order to create the "ports" instance.
  • visual_learner
    visual_learner about 15 years
    Also note: To deal with FILE * pointers and not struct FILE * pointers, you need to use the "typedef" version. The above code requires "struct port_t". If it were "typedef struct port_t { ... } PORT" then it could use a PORT * pointer similar to FILE * pointers.
  • paxdiablo
    paxdiablo about 15 years
    @Chris, it doesn't have to be declared fully, an implementation could technically define a FILE struct as char[X] since there's nothing in the standard that dictates what the structure contains - so it could be hidden.
  • Michael Burr
    Michael Burr about 15 years
    But, sure enough, Chris is right - it seems all my compilers have the full FILE structure defined in stdio.h. I had always assumed they wouldn't - I wonder if there's something that makes them have to, or if it's just convenient and the implementers don't care that the struct is fully available.
  • Jonathan Leffler
    Jonathan Leffler about 15 years
    The reason the file structure is laid out in <stdio.h> is so that the macros like getchar() can be defined - the compiler needs the internals.
  • Steve Melnikoff
    Steve Melnikoff about 15 years
    @Matthew: it may be worth clarifying that it's the full type defintion that needs to be in the header file; the variable definition goes in the source file.
  • Jason
    Jason about 15 years
    he wasn't defining a variable in a header, he was trying to forward declare the port_t type.
  • eaanon01
    eaanon01 about 15 years
    Why he is not using get/set or simulair functions beats me... But yea you are correct... I was just giving a suggestion...
  • Matthew
    Matthew about 15 years
    Steve is correct, of course. C++ is the same, even with classes. You need the full class definition in the header so the compiler knows how much space it should reserve on the stack for variables of that type. Only the implementation of member functions need not be in the header file.
  • Johannes Schaub - litb
    Johannes Schaub - litb about 15 years
    Evan, in C it is not a struct definition, but a struct declaration if you do struct f { ... }; in C++, that is called a definition, in C there is no such distinction between a struct definition and a struct declaration: both a declarations. the first ("struct f;") declares an incomplete type...
  • Johannes Schaub - litb
    Johannes Schaub - litb about 15 years
    while the second ("struct f { int a; };") declares a complete type struct f. so his first wording "full declaration" was quite correct (for C) i think. for C++, "full definition" would be better because that's precisely what "struct f;" is not in C++.
  • Johannes Schaub - litb
    Johannes Schaub - litb about 15 years
    Evan, C also handles it different regarding incomplete types used in object definition: struct c; struct c f; is completely valid in C, as long as later in the translation unit a declaration of struct c provides the complete type. (until then, struct c remains an incomplete type).
  • Johannes Schaub - litb
    Johannes Schaub - litb about 15 years
    and in between struct c f; and the declaration that provides the complete type, f can be used in limited ways (e.g its address can be taken, but sizeof cannot be applied). In C++, however, "struct c; struct c f;" would be wrong because struct c is an incomplete type. c++ is more restrictive here.
  • Johannes Schaub - litb
    Johannes Schaub - litb about 15 years
    so i said C handles that differently than C++. (declarations can be definitions for objects, enum consts, functions and typedef-names - not for structs/unions in C. But in C++, there is also a class definition (with class/struct class-key). that's kinda confusing, but sadly, that's how it is :)
  • Johannes Schaub - litb
    Johannes Schaub - litb about 15 years
    You can read about that in C99 (i've got the TC2 n1124 document) 6.7 (especially, 6.7/5). i think C surprises me everytime again. rules in it are sometimes a bit surprising for me. but maybe that is just because they are different from the rules of c++.