I am currently writing a C program with a struct called Rectangle. The code below shows how I set it up.
typedef struct {
int width;
int height;
int x;
int y;
} Rectangle;
After that, I made another struct called Ellipse which contained exactly the same values as the Rectangle struct, as well as some more.
I wanted to keep my code neat so I decided to make a base struct called Shape.
I used this Shape struct in the header of my other structs.
typedef struct {
int width;
int height;
int x;
int y;
} Shape;
typedef struct {
Shape shape;
} Rectangle;
typedef struct {
Shape shape;
int angle;
int anchor_x;
int anchor_y;
} Ellipse;
Now whenever I make an instance of one of these structs, VSCode thinks there's an error.
Rectangle *rect;
rect -> width = 100;
VSCode puts an error squiggle under width that says struct "<unnamed>" has no field "width", but when I compile the code, it works perfectly.
Why does VSCode raise this error? Should I be doing things differently? How can I stop it from making unnecessary squiggles?
Please be patient, I am new to C programming.
You don't have a field width inside Rectangle - you have a field shape. Presumably what you wanted to do is rect->shape.width = 100.
Notice that your code won't work as-is because you never allocate memory for rect.
typedef struct
{
int x1,y1,x2,y2;
int (*division_mode_x)(int i,int x1,int x2,SpriteGrid grid);
int (*division_mode_y)(int i,int y1,int y2);
}SpriteGrid;
Do you think this is a valid way to use function pointers inside struct?
Note : Please don't say try and see it for yourself. There is no problem with compilation. I just wanna know if this is a standard property of the C language. Will it also compile in other compilers?
It doesn't compile on gcc, clang or tinycc, and it shouldn't.
Before the typedef ends, SpriteGrid is not a thing so you can't use it. Forward declaring the struct (with a tag) and the typedef should fix it.
typedef struct SpriteGrid SpriteGrid;
typedef struct SpriteGrid /*this typedef is redundant now*/
{
int x1,y1,x2,y2;
int (*division_mode_x)(int i,int x1,int x2,SpriteGrid grid);
int (*division_mode_y)(int i,int y1,int y2);
}SpriteGrid;
Alternatively, you can do
typedef struct SpriteGrid
{
int x1,y1,x2,y2;
//without the forward typedef `SpriteGrid` isn't usable
//here yet, but `struct SpriteGrid` is
int (*division_mode_x)(int i,int x1,int x2,struct SpriteGrid grid);
int (*division_mode_y)(int i,int y1,int y2);
}SpriteGrid;
relying on the fact that a tag becomes usable immediately after struct tag.
I am using some code made by someone else, to implement a kalman filter into my imu with arduino. I understand the vast majority of it and the maths behind it, but i am having some errors when implementing it which i cannot understand (serious lack of knowledge on typdefs and structs and initializing them). If someone could explain this error to me it would be much appreciated.
The header file contains this...
struct kalman_data{
float x1, x2, x3;
float p11, p12, p13,
p21, p22, p23,
p31, p32, p33;
float q1, q2, q3;
};
typedef struct _kalman_data kalman_data;
void kalman_data(kalman_data* data);
void kalman_calc(kalman_data* data, float z1, float z2);
My arduino code contains this..
kalman_data pitch_data;
kalman_data roll_data;
void loop(){
kalman_data(&pitch_data);
kalman_data(&roll_data);
kalman_calc(&pitch_data, pitch, gyro_yz);
kalman_calc(&roll_data, roll, gyro_xz);
}
And this is the error i get...
In file included from test.ino:2:0:
E:\Users\Alexander\Documents\Arduino\libraries\Kalman/kalman.h:30:29: error: conflicting declaration 'typedef struct _kalman_data kalman_data'
typedef struct _kalman_data kalman_data;
E:\Users\Alexander\Documents\Arduino\libraries\Kalman/kalman.h:17:8: error: 'struct kalman_data' has a previous declaration as 'struct kalman_data'
struct kalman_data{
struct kalman_data{
should be
struct _kalman_data{
in order to correspond to the subsequent
typedef struct _kalman_data kalman_data;
Then, the function
void kalman_data(kalman_data* data);
should better be renamed. As I recall both C and C++ allow you to reuse a type name for a function, to have both in scope at the same time, but even if that's allowed it's absolutely not a good idea. Very confusing.
The struct definition is reserving the name kalman_data and the typedef is trying to reserve the name again, for a struct called _kalman_data. This causes the error.
To rectify this, use struct _kalman_data and then the typedef will work as intended.
The function getManager creates a Manager struct and returns a pointer to it from the type ManagerP (This function works ok). The definitions are like this :
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
typedef struct Manager *ManagerP;
//My little code (that does the problem) is this (it's inside main):
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000); //this works ok.
foundId = manToFind->ID; //Error : "dereferencing pointer to incomplete type"
Can you please help me finding the problem ? I don't understand what this error mean.
Thanks.
EDIT:
Thanks but I just noticed a problem.
These lines are inside "Manager.c".
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
typedef struct Manager *ManagerP;
In my main file I do include "Manager.h" that has some more definitions.
I just checked and when I'm moving the two typedefs code (written above) to the main file, everything works properly. But I need these typedefs to be inside "Manager.c" (and then I still get a "dereferencing pointer to incomplete type" error. So what is the problem ??
Edit #2 :
Ok I'm posting the three files. When I compile those I get the error :
"GenSalary.c:9:21: error: dereferencing pointer to incomplete type"
These are the files :
// *Manager.h* :
#ifndef MANAGER_H
#define MANAGER_H
#define MAX_NAME_LENGTH 30
typedef struct Manager *ManagerP;
ManagerP getManager(int ID, const char name[], double paycheck,
double attract, int numberOfStudentsInSchool);
#endif
// *Manager.c* :
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "Manager.h"
#define MAX_PRINT_LENGTH 1000
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
ManagerP getManager(int ID, char const name[], double paycheck,
double attract, int numberOfStudentsInSchool)
{
ManagerP retVal = (ManagerP) malloc(sizeof(struct Manager));
if (retVal == NULL)
{
fprintf(stderr, "ERROR: Out of memory in Manager\n");
exit(1);
}
retVal->ID = ID;
strcpy(retVal->name, name);
retVal->paycheck = paycheck;
retVal->attract = attract;
retVal->numberOfStudentsInSchool = numberOfStudentsInSchool;
return retVal;
}
// *GenSalary.c* :
#include <stdio.h>
#include <stdlib.h>
#include "Manager.h"
int main()
{
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000); //this works ok.
foundId = manToFind->ID; //Error : "dereferencing pointer to incomplete type"
return 0;
}
I compile it using gcc -Wall GenSalary.c Manager.c -o GenSalary and i'm getting :
GenSalary.c:9:21: error: dereferencing pointer to incomplete type
NOTE : I CAN'T CHANGE THE MANAGER FILES (THEY BELONG TO EXERCISE)I CAN CHANGE ONLY MAIN.
Thanks for helping !
As written, getManager looks like it intends the returned pointer to be opaque. If that is the case, it would be usual to provide functions for anything the caller should be able to do. For example:
manager.h
...
typedef struct Manager *ManagerP;
ManagerP getManager(int ID, const char name[], double paycheck,
double attract, int numberOfStudentsInSchool);
int getManagerID(ManagerP);
manager.c
...
int getManagerID(ManagerP m) { return m->ID; }
gensalary.c
...
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000);
foundId = getManagerID(manToFind);
The alternative is to move the definition of your struct into the header, where everything can see it (at the moment it is forward-declared in the header, but only manager.c know what is inside).
The code below works fine with gcc -Wall -pedantic -o test test.c. I am unsure, however, that hiding pointer types using typedefs has any real advantages to readability. The error must come from somewhere in the context of your code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Manager
{
int ID;
char name[42];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
typedef struct Manager *ManagerP;
ManagerP getManager(int x, char *y, double z, double q, int p)
{
ManagerP foo = malloc(sizeof(Manager));
foo->ID = x;
strncpy(foo->name, y, 42);
foo->numberOfStudentsInSchool = p;
foo->paycheck = z;
foo->attract = q;
return foo;
}
int main(void)
{
int foundId;
ManagerP manToFind = getManager(1, "manager2", 200.0 , 1.0, 1000);
foundId = manToFind->ID;
printf("Found ID: %d\n", foundId);
return 0;
}
From your own edit:
I just checked and when I'm moving the two typedefs code (written
above) to the main file, everything works properly. But I need these
typedefs to be inside "Manager.c"
You need to include these definitions for it to work, as you've found. Put them in "Manager.h" and include "Manager.h" in both your main file, and in "Manager.c".
EDIT: From your code, you need to include the typedef of the actual struct in the header file, as well, not just the typedef of the pointer, so move this:
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
out of "Manager.c", and put it immediately before the typedef of ManagerP. Otherwise, all the main file sees is the declaration of the pointer, and it has no information of what the struct actually contains, hence the "incomplete type" error you're getting.
EDIT 2: If you "CAN'T CHANGE THE MANAGER FILES" as you say, then it's a bit of a silly question, since you can't apply the best answer, but if that actually is true, then you'll just have to copy and paste the struct definition into "GenSalary.c" (or into a new, user-created header file, if you need to use it in other files, too), because that file needs it. Defining the struct separately in both "GenSalary.c" and "Manager.c" is a bad idea for lots of reasons, but it is perfectly legal C, and it'll work (that's all that's happening under the hood when you #include a header file, anyway).
The line of doing the typedef for ManagerP will compile since it is a pointer declaration however since the struct Manager is in the file Manager.c and is not available to GenSalary.c the compiler is unable to know what the struct Manager looks like.
So the include file Manager.h needs to have the following lines of code.
typedef struct Manager
{
int ID;
char name[MAX_NAME_LENGTH];
int numberOfStudentsInSchool;
double paycheck;
double attract;
} Manager;
typedef struct Manager *ManagerP;
Then any source file that includes Manager.h will have the definition of the Manager typedef as well as the ManagerP typedef. And when the ManagerP is dereferenced, the compiler will know how to access the various parts of the Manager struct.
Edit: Other considerations
You mention that this is an exercise of some kind so I would like to note that the way this is being done, the struct in a file and the only thing exposed is a pointer to the struct, is a mechanism often used to hide struct details. The goal of this technique is to provide a pointer to an object within a library, the struct in this case, however the person using the library is not to access any of the struct members or to do anything other than pass the pointer to other functions in the library.
So it may be that the point of this exercise is to not access any of the struct members.
When you create a pointer to a type, the compiler does not need to know what that type looks like, because all pointers are the same size (4 or 8 or however many bytes). However, if you attempt to dereference that pointer, the compiler must know what the type looks like in order to calculate memory offsets and perform other tasks. Since in your original cpp file the type Manager is not defined, only declared, the compiler cannot determine what memory offset it needs to use before it can reach the ID field. (A type like this is often called opaque.) Thus the compiler informs you that the type is incomplete.
The same issue would occur if you attempted to create a variable of type Manager directly, because the compiler does not know how much memory is required to be set aside for this variable. You could malloc a pointer to Manager, but if you tried to do sizeof(Manager), it would fail.
In order for this to work, the compiler needs to know what the type looks like at the point where you attempt to dereference the pointer. Thus, the struct definition must be placed within the main cpp file, or within any of the headers which are included by that cpp file.
So I'm morelikely running in a cross reference issue in C
Hello, (I couldnt write it in first for some reason)
Basicly this code:
structA.h:
#pragma once
#include "structB.h"
typedef struct
{
B b;
}A;
structB.h:
#pragma once
#include "structA.h"
typedef struct
{
int field;
}B;
void func(A* a);
structB.c:
#include "structB.h"
void func(A* a)
{
}
Produce the follwing errors on VC2010:
structa.h(7): error C2016: C requires that a struct or union has at
least one member structa.h(7): error C2061: syntax error : identifier
'B' etc
so since I only have a pointer to A in func(A* a) I try doing a forward declaration like this:
#pragma once
typedef struct A;
typedef struct
{
int field;
}B;
void func(A* a);
and I add #include "structA.h" in structB.c
However this doesnt work, to fix it I have to change the param of func(A* a) to func(struct A* a) in prototype and implementation...
But in this case i lose the purpose of typedef-ing my structs...
I know i could simply move the function to another file, but the function is related to my structure so I'd like to keep the prototype in the same file than my struct.
Now maybe thats not a good way to do thing in C, i'm mostly used to C++ so i tend to think in C++ when doing C wich is often problematic...
Does someone know a workaround? Thank you very much.
typedef struct structA;
How did this even compile? -- Correctly:
typedef struct A A;