Redundant naming in C/C++ typedefs/structs
#include <stdio.h>
#include <string.h>
const int NAMELEN=30;
const int MAXCLASSSIZE=10;
typedef struct StudentRec {
char lastname[NAMELEN];
char firstname[NA开发者_StackOverflow社区MELEN];
long int ID;
int finalmark;
}Student;
I'm new to coding..and I have a question about why there is Student; after the bracket.. is it a format that we have to follow.
you are confusing two things. In C you can define a struct like this:
struct foo {
int a, b;
};
Then to use one you have to do this:
struct foo myFoo;
This is really wordy, so they had this brilliant idea of using typedef to make a new type. I can do something like this:
typedef int myInt;
and then use it:
myInt x;
So what you're doing is declaring that there is a new type, Student, which is equivalent to a struct StudentRec. By convention, many people use the same name for the typedef as for the struct - it is legal:
typedef struct foo { int a, b; } foo;
This is creating a typename "Student" to mean the struct. Using typedef
for this purpose is unnecessary in C++. It could be defined like this:
struct Student {
char lastname[NAMELEN];
char firstname[NAMELEN];
long int ID;
int finalmark;
};
In C there are different namespaces for struct names and type names (such as int) {the type namespace is shared with the variable and function namespace, so be aware of that}. When you define a new struct you automatically add its name to the struct namespace, but when you declare a variable of that type you have to preceed it's name with struct
so that the compiler knows to look in the struct namespace to see what exactly it is that you want this variable to be.
Using the typedef keyword you can add a name for the variable to the type namespace so that you do not have to use the struct keyword in your declarations.
The example you gave combined the typedef declaration with the struct definition, but used different names for the struct in the type namespace and the struct namespace. You are able to do this for two reasons. First, prefixing a statement which looks exactly like a variable declaration with typedef defines a typename instead of a variable with the name specified. Secondly, you can declare variables of a struct type by including their names immediatly after the struct declaration and the semicolon. Your example combined these.
There are other legal forms of this in C. For example:
/* This declares a variable foo whose type has no name but is a struct that contains one int named x */
struct {
int x;
} foo;
/* This adds bar to the type namespace without adding an entry to the struct namespace. */
typedef struct {
int y;
} bar;
/* This adds the name baz to the struct namespace and declares a variable named b of this type */
struct baz {
int z;
} b;
/* This adds the name ralf to the type namespace which also refers to this type */
typedef struct baz ralf;
C++ has different namespace structure, which I'm sure you have noticed since it has the namespace keyword. In this instance though C++ is more simple than C. Defining a struct (or class or union or enum) automatically adds the name you used (if any) to the namespace which typedef adds names to. This simplifies things greatly, for the most part, but there are a few gotchas. These mostly have to do with retaining backward compatibility with C. Mostly this compatibility has to do with noticing when someone typedefs struct foo foo;
and not treating it as an error of trying to name something with an already used name.
Another issue comes up with this type of fairly common C code:
struct shoe {
int size;
} shoe;
This is common in C particularly when only one of a struct needs to exist. In C this would be easy because there would be no collision between the names of the struct shoe
and the variable shoe
. In C++ this still works though to maintain backwards compatibility with C.
None of this applies to C++
. In C++
prefer:
struct Foo
{
. . .
};
The rest only applies to C
.
Technically struct Foo {};
is sufficient for most purposes. However it is a bit verbose to use as struct
must be repeated each time type Foo is used.
struct Foo {}
void func( struct Foo* foo );
A typedef makes this simpler.
struct Foo { };
typedef struct Foo Foo;
void func( Foo* foo );
This can be further shortened with:
typedef struct Foo { } Foo;
void func( Foo* foo );
When doing a one liner it's also possible to use this syntax:
typedef struct { } Foo;
void func( Foo* foo );
This is creating an anonymous struct
and then giving it the name Foo. You see this most often with enum
s.
typedef enum { } Bar;
There is a reason the intial redundant Foo is usually left there. It is only only way to create a self referencing struct, like a linked list.
typedef struct Node
{
Node* next;
} Node;
If the initial Node
where ommited there would be no way to declare a pointer to the struct. Technically this is valid as well, but now you have to come up with 2 names, instead of just one.
typedef struct node_
{
node_* next;
} Node;
So why use:
typedef struct Foo { } Foo;
For uniformity. This declaration style covers all you bases, so you never have to think about it when declaring a struct.
Student is the name of the new type the typedef has created. StudentRec is the name of the structure it defines.
精彩评论