I have a struct declaration in C that looks something like this:
static struct {
int a;
int b;
} myStruct[10];
I want to declare a struct member variable inside myStruct, so I try to add this:
static struct {
int c;
int d;
struct myStruct[10] s;
} myNestedStruct[100];
I'm getting a bunch of errors i.e. syntax error before or at: [ and
syntax requires ";" after last struct/union member. What would the better way to implement the nested structs be?
EDIT: My code now looks like this:
static struct {
int a;
int b;
} myStruct[10];
static struct {
int c;
int d;
struct myStruct s[10];
} myNestedStruct[100];
However I'm getting an error: incomplete struct/union/enum myStruct: s
You need to declare myStruct first before using it as a struct type.
struct myStruct {
int a;
int b;
};
static struct {
int c;
int d;
struct myStruct s[10];
} myNestedStruct[100];
This creates a variable called myNestedStruct which is an array of 100 structs, each containing two ints and an array of 10 mystructs.
When you write code like
struct { ... } Foo;, it's not declaring a type named Foo but a variable. Its type is an anonymous struct corresponding to what you put in the curly braces. If you want to declare a type, write struct Foo { ... };.
That's where your error is coming from -- myStruct is not a type name, so when you write struct myStruct in the definition of myNestedStruct the compiler thinks you're about to define a struct by that name. But then it encounters an [ which shouldn't be the next token in a struct declaration ever so it tells you can't make sense of the code.
Related
I read a tutorial in which there is this struct:
struct
{
char Name[25];
int Age;
float SkillRating;
} Employee;
defines a new aggregate, called Employee, containing fields called Name (of type character), Age (of type integer), and SkillRating (of type float).
In contrast, the C statement:
struct EmployeeType
{
char Name[25];
int Age;
float SkillRating;
};
does not define a new aggregate variable, but defines a new aggregate type,
EmployeeType.
This new data type could then be used to declare variables in the
same way as a primitive data type. That is, in the same way that C allows the
variable x to be declared as an integer using the statement
I am confused here. Does the distinction exist if place 'Emplyee` on different position?
I guess they are identical.
In the first case, the struct is unnamed and Employee is a variable of that unnamed struct. You can directly modify it like this:
int main()
{
Employee.Age = 100;
return 0;
}
In the second case, EmployeeType is just a type, but you didn't make any instance of it yet. You can make any amount of instances:
int main()
{
struct EmployeeType a; // employee on the stack
a.Age = 100;
struct EmployeeType *b = malloc(sizeof(struct EmployeeType)); // employee on the heap
if (b) { // set the age of b if the allocation succeeded
b->Age = 100;
}
free(b); // malloc-allocated memory must be freed afterwards
return 0;
}
You can even do both at once:
struct EmployeeType
{
char Name[25];
int
Age;
float SkillRating;
} Employee;
Here, Employee is one instance of it, but you can make additional instances:
int main()
{
Employee.Age = 100;
struct EmployeeType a; // employee on the stack
a.Age = 100;
return 0;
}
struct A_s { int memb; }; // declares a struct A_s
struct A_s a; // declares a variable a of type struct A_s
now you can combine struct declaration with variable declaration:
// declares struct A_s and in the same line declares variable a
struct A_s { int memb; } a;
Now you can create an anonymous struct by omitting the structure tag name:
// declares anonymous struct and in the same line declares variable a
struct { int memb; } a;
Now structure declaration can be really put anywhere:
int func(int a, struct A_s { int memb; } b);
struct A_s { int memb; } func(int a);
struct B_s {
int memb1;
struct A_s {
int memb2;
} a;
};
I think the description of the C code of the field "name" in your post is invalid. The field name inside "aggregate" (read as: structure) has the type "array of 25 characters", not character type.
struct keyword in C can be used to declare aggregate datatypes, aggregate data objects or both.
In your first declaration (and definition), a tag name is missing, so an anonymous object 'Employee' is created. 'Employee' remains the only object of this struct. You cannot create more objects from this struct anywhere else in the code.
In your second declaration, you have created a struct type which can be instantiated many times (i.e., multiple instances of this struct can exist) as shown below -
struct EmployeeType employee_1;
struct EmployeeType employee_2;
Both these syntax are useful depending on the use case.
I have a bit of confusion between the below declarations - could you please help clear it up?
typedef struct {
int a;
int b;
} example;
And this
struct something {
int a;
int b;
} ob;
And I am not sure what the below would even mean?
typedef struct foo {
int a;
int b;
} bar;
typedef struct {
int a;
int b;
} example;
This one defines an unnamed structure type and introduces example as a type alias for that structure type. You can therefore refer to that structure type only as `example.
struct something {
int a;
int b;
} ob;
This one defines a structure type something and also declares an object ob of that type. You can refer to the structure type only as struct something.
typedef struct foo {
int a;
int b;
} bar;
This one defines a structure type named foo and introduces bar as a type alias for that structure type. You can refer to that structure type as struct foo or as bar.
With
typedef struct {
int a;
int b;
} example;
you define an unnamed structure, but define a type-alias example for the structure. That means you can only create instance of the structures using the example "type", like e.g.
example my_example_structure;
With
struct something {
int a;
int b;
} ob;
you define a structure named something, and an instance (a variable) of that structure named ob. You can use struct something to create new variables of the structure:
struct something my_second_ob;
The variable ob can be used like any other instance of the structure:
printf("b = %d\n", ob.b);
Lastly, with
typedef struct foo {
int a;
int b;
} bar;
you define a structure named foo, so you can use e.g. struct foo to define variables. You also define a type-alias bar which can also be used. Like for example
struct foo my_first_foo;
bar my_second_foo;
The general syntax for typedef is
typedef <actual type> <alias name>;
In the last case of your examples, the <actual type> is
struct foo {
int a;
int b;
}
and the <alias name is bar.
I have a struct that declared as follow:
struct a {
struct b {
int d;
} c;
};
How to declare a variable of b outside a? In C++ I can use a::b x;. But, in C it required to specifies struct keyword before struct name.
C has a flat layout; when you declare a struct within another struct, the former is just being put into the global namespace.
So, in your example, it is just struct b.
C does not have nested types. You can't write a::x b or anything that ressembles it. If you want to get rid of the struct keyword, that's another problem. Use typedefs. but it won't allow to nest types.
typedef struct b_t {
int d;
} b;
typedef struct {
b c;
} a;
b some_b;
a some_a;
int f() {
some_b.d=42;
some_a.c=some_b;
return 0;
}
.
I've seen C structs declared several different ways before. Why is that and what, if anything, does each do different?
For example:
struct foo {
short a;
int b;
float c;
};
typedef struct {
short d;
int e;
float f;
} bar;
typedef struct _baz {
short a;
int b;
float c;
} baz;
int main (int argc, char const *argv[])
{
struct foo a;
bar b;
baz c;
return 0;
}
Well, the obvious difference is demonstrated in your main:
struct foo a;
bar b;
baz c;
The first declaration is of an un-typedefed struct and needs the struct keyword to use. The second is of a typedefed anonymous struct, and so we use the typedef name. The third combines both the first and the second: your example uses baz (which is conveniently short) but could just as easily use struct _baz to the same effect.
Update: larsmans' answer mentions a more common case where you have to use at least struct x { } to make a linked list. The second case wouldn't be possible here (unless you abandon sanity and use a void * instead) because the struct is anonymous, and the typedef doesn't happen until the struct is defined, giving you no way to make a (type-safe) pointer to the struct type itself. The first version works fine for this use, but the third is generally preferred in my experience. Give him some rep for that.
A more subtle difference is in namespace placement. In C, struct tags are placed in a separate namespace from other names, but typedef names aren't. So the following is legal:
struct test {
// contents
};
struct test *test() {
// contents
}
But the following is not, because it would be ambiguous what the name test is:
typedef struct {
// contents
} test;
test *test() {
// contents
}
typedef makes the name shorter (always a plus), but it puts it in the same namespace as your variables and functions. Usually this isn't an issue, but it is a subtle difference beyond the simple shortening.
It's largely a matter of personal preference. I like to give new types a name starting with a capital letter and omit the struct, so I usually write typedef struct { ... } Foo. That means I cannot then write struct Foo.
The exception is when a struct contains a pointer to its own type, e.g.
typedef struct Node {
// ...
struct Node *next;
} Node;
In this case you need to also declare the struct Node type, since the typedef is not in scope within the struct definition. Note that both names may be the same (I'm not sure where the underscore convention originated, but I guess older C compilers couldn't handle typedef struct X X;).
All your uses are syntactically correct. I prefer the following usage
/* forward declare all structs and typedefs */
typedef struct foo foo;
.
.
/* declare the struct itself */
struct foo {
short a;
int b;
foo* next;
};
Observe that this easily allows to use the typedef already inside the declaration of the struct itself, and that even for struct that reference each other mutually.
The confusion comes about because some of the declarations are in fact declaring up to three C constructs. You need to keep in mind the difference between:
A typedef declaration,
A struct definition, and
A struct declaration.
They are all very different C constructs. They all do different things; but you can combine them into the one compound construct, if you want to.
Let's look at each declaration in turn.
struct foo {
short a;
int b;
float c;
};
Here we are using the most basic struct definition syntax. We are defining a C type and give it the name foo in the tag namespace. It can later be used to declare variables of that type using the following syntax:
struct foo myFoo; // Declare a struct variable of type foo.
This next declaration gives the type another name (alias) in the global namespace. Let's break it down into its components using the previous basic declaration.
typedef foo bar; // Declare bar as a variable type, the alias of foo.
bar myBar; // No need for the "struct" keyword
Now just replace "foo" with the the struct's definition and voila!
typedef struct {
short d;
int e;
float f;
} bar;
typedef struct _baz {
short a;
int b;
float c;
} baz;
The above syntax is equivalent to the following sequence of declarations.
struct _baz {
short a;
int b;
float c;
}
typedef _baz baz; // Declare baz as an alias for _baz.
baz myBaz; // Is the same as: struct _baz myBaz;
I have a struct defined as:
struct {
char name[32];
int size;
int start;
int popularity;
} stasher_file;
and an array of pointers to those structs:
struct stasher_file *files[TOTAL_STORAGE_SIZE];
In my code, I'm making a pointer to the struct and setting its members, and adding it to the array:
...
struct stasher_file *newFile;
strncpy(newFile->name, name, 32);
newFile->size = size;
newFile->start = first_free;
newFile->popularity = 0;
files[num_files] = newFile;
...
I'm getting the following error:
error: dereferencing pointer to incomplete type
whenever I try to access the members inside newFile. What am I doing wrong?
You haven't defined struct stasher_file by your first definition. What you have defined is an nameless struct type and a variable stasher_file of that type. Since there's no definition for such type as struct stasher_file in your code, the compiler complains about incomplete type.
In order to define struct stasher_file, you should have done it as follows
struct stasher_file {
char name[32];
int size;
int start;
int popularity;
};
Note where the stasher_file name is placed in the definition.
You are using the pointer newFile without allocating space for it.
struct stasher_file *newFile = malloc(sizeof(stasher_file));
Also you should put the struct name at the top. Where you specified stasher_file is to create an instance of that struct.
struct stasher_file {
char name[32];
int size;
int start;
int popularity;
};
How did you actually define the structure? If
struct {
char name[32];
int size;
int start;
int popularity;
} stasher_file;
is to be taken as type definition, it's missing a typedef. When written as above, you actually define a variable called stasher_file, whose type is some anonymous struct type.
Try
typedef struct { ... } stasher_file;
(or, as already mentioned by others):
struct stasher_file { ... };
The latter actually matches your use of the type. The first form would require that you remove the struct before variable declarations.
the case above is for a new project. I hit upon this error while editing a fork of a well established library.
the typedef was included in the file I was editing but the struct wasn't.
The end result being that I was attempting to edit the struct in the wrong place.
If you run into this in a similar way look for other places where the struct is edited and try it there.
The reason why you're getting that error is because you've declared your struct as:
struct {
char name[32];
int size;
int start;
int popularity;
} stasher_file;
This is not declaring a stasher_file type. This is declaring an anonymous struct type and is creating a global instance named stasher_file.
What you intended was:
struct stasher_file {
char name[32];
int size;
int start;
int popularity;
};
But note that while Brian R. Bondy's response wasn't correct about your error message, he's right that you're trying to write into the struct without having allocated space for it. If you want an array of pointers to struct stasher_file structures, you'll need to call malloc to allocate space for each one:
struct stasher_file *newFile = malloc(sizeof *newFile);
if (newFile == NULL) {
/* Failure handling goes here. */
}
strncpy(newFile->name, name, 32);
newFile->size = size;
...
(BTW, be careful when using strncpy; it's not guaranteed to NUL-terminate.)
The reason is you did not declare type struct stasher_file, you define a struct variable stasher_file
instead.
In C, the declaration of structure:
struct structure-tag {
member1
member2
...
};
structure-tag is an optional name following the keyword struct.
After declaration, you can define a variable:
struct structure-tag var1, *var2;
Also, you can do both declaration and definition like:
struct structure-tag {
member1
member2
...
} var1, *var2;
So in your case, you could try this:
struct stasher_file {
char name[32];
int size;
int start;
int popularity;
} *files[TOTAL_STORAGE_SIZE];
struct stasher_file *newFile = malloc(sizeof(struct stasher_file));
... other code ...
That's all.