C Struct : typedef Doubt ! - c

In the given code snippet, I expected the error symbol Record not found. But it compiled and ran fine on Visual Studio 2010 Compiler. I ran it as a C program from Visual Studio 2010 Command Prompt in the manner -
cl Record.c
Record
Now the doubt is, doesn't typedef check for symbols ? Does it work more like a forward declaration ?
#include "stdio.h"
#include "conio.h"
typedef struct Record R;
struct Record
{
int a;
};
int main()
{
R obj = {10};
getch();
return 0;
}

You can always refer to undefined structures, which is a typical way to implement linked lists, after all. They just have to be defined when you want to make use of their fields.
This page contains some details.

C does not find the symbol Record because it is declared later on the code, like if you were trying to use a function you declare past on the code without defining its prototype.
You can also combine the two declarations, and then it becomes:
typedef struct Record
{
int a;
} R;
It also works and, in my opinion, even better, not because it can be faster, but because it is smaller.

typedef must be used after its first parameter has been defined.
struct Record
{
int a;
};
typedef struct Record R;
or
typedef struct Record
{
int a;
} R;
If you need to use struct Record within the struct, just use struct Record:
typedef struct Record
{
struct Record *next;
}
typedef struct Record R;

Related

Header file typedef definition

Hi I was triying to make something like this, but I cant sort it out. The problem is one typedef needs the other one. I would really appreciate someones help!
#ifndef SHELL_DATA_H
#define SHELL_DATA_H
#include <buffer.h>
#define COMMANDS 10
#define MAX_ARGS 4
typedef struct {
void (*command)(int, char **, t_shellData *shelldData);
char *name;
char *description;
} t_command;
typedef struct {
t_command commands[COMMANDS];
t_buffer buffer;
char username[BUFFER_SIZE];
} t_shellData;
#endif
typedef struct command t_command;
typedef struct shelldata t_shellData;
struct command {
void (*command)(int, char **, t_shellData *shelldData);
char *name;
char *description;
};
struct shelldata {
t_command commands[COMMANDS];
t_buffer buffer;
char username[BUFFER_SIZE];
};
should fix it up for you. The structure tag and typedef name can be the same; I just renamed them for clarity.
C is a simple language, with an underlying principle of do not surprise people. For this reason, entities in C need to be declared or defined before they are used. As a simple example:
int f() {
int a = 7;
int b = a;
....
}
is OK, but this is not:
int f() {
int b = a;
int a = 7;
....
}
and while not exactly, languages like golang permit this -- the compiler will root around and find the definition you obviously wanted.
Typedef, in C, really just puts an entry into the symbol table; it is like a define, but less blunt, so the line:
typedef struct a A;
Serves to inform the compiler of two things: somewhere there is a structure with tag a, and I want A to be a shortform for it. There is another form of this:
struct a;
typedef struct a A;
Here, the first line tells the compiler "I want you to know about a thing called struct a"; and the second line "I want an alias to that struct a thing called A".
So, as the compiler progresses through the source, it knows that an A means a struct a, and even if it hasn't seen the definition of struct a, it has a placeholder.
But, if you attempted, before defining struct a to define another structure:
struct b {
struct a stuff;
int morestuff;
};
The compiler would complain, because it doesn't know the layout of a struct a; however this:
struct b {
struct a *stuff;
int morestuff;
};
is OK, because it knows how big a pointer is, and can defer its understanding of a struct a until it needs it.
So, Summary: declare or define data types before you attempt to use them. The C compiler requires it. A declaration is ok, unless you need the actual layout of it, in which case a definition is required.
Good Luck.

dereferencing pointer to incomplete type in C

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.

Why can't we typedef an (unnamed) structure twice at file scope, but we can typedef "int" twice without error?

The following code compiles and runs fine:
#include <stdio.h>
typedef int Someint;
typedef int Someint;
int main()
{
Someint b = 4;
printf("%d", b);
return 0;
}
The following code doesn't compile. It's giving me an error conflicting types for 'Somestruct'.
#include <stdio.h>
typedef struct
{
int x;
}
Somestruct;
typedef struct
{
int x;
}
Somestruct;
int main()
{
Somestruct b;
b.x = 4;
printf("%d", b.x);
return 0;
}
Why can I typedef one type (int in first code) twice without error ,but the same thing fails for another type (the structure above)? What is the difference between the two cases?
I'm using the MinGW compiler that came with CodeBlocks 12.11.
The thing is that when you do:
typedef struct
{
} Somestruct;
It creates an anonymous struct - you can expect some hidden implementation-defined guaranteed-unique placeholder identifier to be used - for which you specify the typedef. So, when you do it twice you get a conflict in having the same typedef-ed name asked to refer to two distinct structures. With int, you're simply repeating the original. If you give the struct an actual name then that lets you repeat the typedef:
typedef struct Somestruct
{
} Somestruct;
Because you're defining your typedef using an anonymous struct, both definitions are distinct.
The following doesn't do this, and works. (note that you can still only define the struct once)
#include <stdio.h>
typedef struct foo
{
int x;
}
Somestruct;
typedef struct foo Somestruct;

A reused named struct as a nested struct triggers a redefinition error in GCC

This is a contrived example, but expresses the core problem. I have a union and a structure with the same nested structure from an existing code base:
typedef union _MyUnion
{
unsigned int A;
struct _MyNestedStruct
{
int field
} MyNestedStruct;
} MyUnion;
and
typedef struct _MyStruct
{
struct _MyNestedStruct
{
int field
} MyNestedStruct;
} MyStruct;
If I compile this under the Green Hills Compiler (GHC), then there are no problems. Compiling under GCC gives the error "error: redefinition of 'struct _MyStruct'".
First of all, why was I able to successfully compile with a named structure as a nested structure? I suspect that GHC is compiling with some C++ rules, or it supports named structures in a nested structure.
Second, what would allow me to successfully compile without any significant code changes? I know I can just delete the _MyNestedStruct from the nested structure, but does this have any consequences?
In C there are no namespace scopes, implicit or explict, so all the structure names share the same name space. Hence, struct _MyNestedStruct is defined twice and it is an error. GCC is correct, GHC is not.
If it were C++, then the code would be correct, because each struct would create a different namespace scope and so there is no name clash.
Solutions that I can think of:
A) If the structures are actually the same, define it just once outside of the other ones (you could have it inside the first one, but that would be weird).
struct _MyNestedStruct
{
int field
};
typedef union _MyUnion
{
unsigned int A;
struct _MyNestedStruct MyNestedStruct;
} MyUnion;
typedef struct _MyStruct
{
struct _MyNestedStruct MyNestedStruct;
} MyStruct;
B) Name the two structures differntly. In C the name is not so important, as long the definition is identical.
C) Use nameless structures. I reckon you will not be using these names at all:
typedef union _MyUnion
{
unsigned int A;
struct
{
int field;
} MyNestedStruct;
} MyUnion;
typedef struct _MyStruct
{
struct
{
int field;
} MyNestedStruct;
} MyStruct;
BTW, remember that any name beginning with and underscore plus an uppercase is reserved for the implementation and should not be defined by the user.

C struct/function cross reference

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;

Resources