Dereferencing pointer to incomplete type 'stru

2019-09-15 05:58发布

问题:

I am attempting to create a type in C that can accept most primitive types. I am new to C and don't understand structs very well. My error occurs on line 10 (of main.c) and it will also occur on line 11 if line 10 is removed (also of main.c). If anyone has an ideas/pointers I would really appreciate it! Many thanks!

main.c:

#include <stdio.h>

#include "modularType.h"

int main()
{
    int data = 1;

    PyType object = createPyObjectInt(data);
    printf("Type of data:  %d\n", object->typeOfData);
    printf("Value of data: %d\n", object->intData);

    return 0;
}

modularType.h:

typedef struct pytype *PyType;

PyType createPyObjectEmpty(void);
PyType createPyObjectInt(int data);

void setDataInt(PyType, int data);
void setDataIntStar(PyType, int* data);

void freeMyType(PyType);
void freeCharStar(PyType);
void freeIntStar(PyType);
void freeFloatStar(PyType);

modularType.c:

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

#ifndef NEW_TYPE
#define NEW_TYPE

#include "modularType.h"

typedef enum
{
    NO_DATA,
    REG_CHAR,
    CHAR_STAR,
    REG_INT,
    INT_STAR,
    REG_FLOAT,
    FLOAT_STAR,
}types;

struct pytype
{
    //The number of data types i can hold here
    unsigned char typeOfData: 3;

    union
    {
        char   charData;
        char*  charStarData;
        int    intData;
        int*   intStarData;
        float  floatData;
        float* floatStarData;
    }
};

PyType createPyObjectEmpty(void)
{
    PyType object;

    object = malloc(sizeof(*object));

    object->typeOfData = NO_DATA;

    return object;
}

PyType createPyObjectInt(int data)
{
    PyType object;

    object = malloc(sizeof(*object));

    object->intData = data;
    object->typeOfData = REG_INT;

    return object;
}

void setDataInt(PyType object, int data)
{
    object->intData    = data;
    object->typeOfData = REG_INT;
}

void setDataIntStar(PyType object, int* data)
{
    object->intStarData = data;
    object->typeOfData  = INT_STAR;
}

#endif

As a side note my compilation command (gcc -Wall -std=c99 -o modType main.c modularType.c) produces the following warning: modularType.c:35:1: warning: no semicolon at end of struct or union. I thought that I had formatted my struct correctly but I have also seen people define structs as following:

typedef struct pytype
{
    //code here
}PyType;

Is this a better way or is the way I am doing it fine?

回答1:

The structure definition is incomplete in the header file, so you cannot refer to any struct members in your code. The compiler complains that it does not know about any struct members at all.

An incomplete structure definition is one where you do not provide the list of members for the implementation. Such a definition allows you to manipulate pointers to such structures, but not access any members since they are not explicitly defined and the compiler needs to know their type and offset from the beginning of the structure to generate the corresponding code.

Also not that the typedef PyType hides a pointer to a struct pytype. It is error prone to hide pointers behind typedefs, leading to confusing code for both the programmer and the reader.



回答2:

The problem you have is one of scope. That is an intentional and inherent part of C. The approach you are trying to take is one of data encapsulation or data hiding. You intentionally declare the struct in modularType.c which provides file scope for the struct. struct pytype is never exposed in main.c making it impossible to directly reference the members of the struct (e.g. object->foo) in main.c. That is by design. That is how you intentionally hide the members of pytype from being directly accessed in main.

To do what you are attempting, you need to expose functions through modularType.h that retrieve the information you want from your struct pytype object. For example, you want retrieve the value for object->typeOfData and object->intData. To do that in main, you simply need functions that provide access to that data. In modularType.c you could add:

int getPyObjectType (PyType object)
{
    return object->typeOfData;
}

int getDataInt (PyType object)
{
    return object->intData;
}

Then in modularType.h you could provide the function prototypes that will expose the functions to main, e.g.

int getPyObjectType (PyType);
int getDataInt (PyType);

Since both functions are in modularType.c, they have access to the members of struct pytype while anything else in main does not. After making the following modifications to main.c

printf("Type of data:  %d\n", getPyObjectType(object));
printf("Value of data: %d\n", getDataInt(object));

You will be able to return the values you desire, e.g.:

Example Use/Output

$ ./bin/main
Type of data:  3
Value of data: 1

Footnote 1: While not an error, the standard coding style for C avoids the use of caMelCase or MixedCase variable names in favor of all lower-case while reserving upper-case names for use with macros and constants. It is a matter of style -- so it is completely up to you, but failing to follow it can lead to the wrong first impression in some circles.



回答3:

You 2 problems:


  1. This part from modularType.c belongs to the beginning of modularType.h and you are missing an ; (see comment int the snippet right below).

    typedef enum
    {
      NO_DATA,
      REG_CHAR,
      CHAR_STAR,
      REG_INT,
      INT_STAR,
      REG_FLOAT,
      FLOAT_STAR,
    } types;
    
    struct pytype
    {
     //The number of data types i can hold here
     unsigned char typeOfData: 3;
    
     union
     {
        char   charData;
        char*  charStarData;
        int    intData;
        int*   intStarData;
        float  floatData;
        float* floatStarData;
      } ;
     // ^ you are missing a ';' here
    };
    

  1. The header guard belongs into modularType.h and not into modularType.c

    #ifndef NEW_TYPE
    #define NEW_TYPE
    ... 
    #endif
    

    This is however not a problem right now. It doesn't prevent your files from compiling, it's just completely useless to put a header guard into a .c file.



回答4:

The way you've done it is fine, except for 2 things.

1) You really shouldn't make it a typedef to a pointer of a struct unless you make it clear from the name that is what it is. Change it to typedef struct pytype PyType;

2) Your header should also include the definitions of struct pytype and the enum as well so that any file that includes it knows what they are.