there is a line in c code:
struct name_1 name2;
what this line implies?
my understanding about above line is name_1 is the name of the structure and name2 is the object variable. However name_1 should have been defined somewhere, but I could not find the definition of name_1.
so my question is; is there anything like this where we can have an object of a structure which is not defined anywhere.
At file scope, this is the definition of a variable called name2 whose type is struct name_1. If there has not been a previous declaration of struct name_1; then this line also declares that type.
Being a file scope variable definition with no initializer nor storage class specifier, this is a tentative definition. Tentative definitions may have incomplete type so long as the type is completed by the end of the file, e.g.:
#include <stdio.h>
struct foo bar;
void f();
int main()
{
printf("%p\n", (void *)&bar);
f();
// cannot do this
// printf("%d\n", bar.x);
}
struct foo { int x; };
void f()
{
bar.x = 5;
}
This sort of code would be uncommon however. If you see struct foo bar; in real code it is more likely that struct foo was previously defined somewhere that you are overlooking.
Is there a header file (name.h) you have included in your c code? Usually, structure, constant and function declarations are in the header file, which is 'included' (at the top of your c file), and you could then use those structures and constants in your c file without defining them
Related
I have a program consisting of two source files (farm.c, init.c) and two corresponding header files (farm.h, init.h) Both source files contain header guards and each other, because they both require functions/variables from each other.
init.h:
#ifndef INIT_H
#define INIT_H
#include<stdio.h>
#include<stdlib.h>
#include"farm.h"
#define PIG_SOUND "oink"
#define CALF_SOUND "baa"
enum types {PIG, CALF};
typedef struct resources {
size_t pork;
size_t veal;
size_t lamb;
size_t milk;
size_t eggs;
} resources;
typedef struct animal {
size_t legs;
char* sound;
int efficiency;
void (*exclaim)(struct animal*);
void (*work)(struct animal*, struct resources*);
} animal;
/* I have tried various ways of declaring structs in addition to
the typedef such as this */
//animal stock;
//animal farm;
void make_pig(struct animal* a, int perf);
void make_calf(struct animal* a, int perf);
#endif
farm.h:
#ifndef FARM_H
#define FARM_H
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include"init.h"
/* GCC does not recognise the typedef or struct identifier
until these forward declarations have been made in
addition to the included init.h header file */
//typedef struct animal animal;
//typedef struct resources resources;
void exclaim(animal* b);
void work(struct animal* b, struct resources* s);
#endif
init.c:
#include"init.h"
void make_pig(animal* a, int perf) {
a->legs = 4;
a->sound = PIG_SOUND;
a->efficiency = perf;
a->exclaim = exclaim;
a->work = work;
}
void make_calf(animal* a, int perf) {
a->legs = 4;
a->sound = CALF_SOUND;
a->efficiency = perf;
a->exclaim = exclaim;
a->work = work;
}
farm.c:
#include"farm.h"
int main() {
return 0;
}
void exclaim(animal* a) {
for (int i = 0; i < 3; i++) {
printf("%s ", a->sound);
}
printf("\n");
}
void work(animal* a, struct resources* r) {
if (!strcmp(a->sound, PIG_SOUND)) {
r->pork += a->efficiency;
}
if (!strcmp(a->sound, CALF_SOUND)) {
r->veal += a->efficiency;
}
}
Using both types of names (i.e.,struct ani and animal) normally works perfectly fine on my Linux system with the C99 standard. However when I use struct ani instead of animal here, I get the below warnings for every instance of the type usage for struct ani and struct resources.
lib/farm.h:10:21: warning: ‘struct ani’ declared inside parameter list will not be visible outside of this definition or declaration
10 | void exclaim(struct ani* a);
| ^~~
lib/farm.h:11:33: warning: ‘struct resources’ declared inside parameter list will not be visible outside of this definition or declaration
11 | void work(struct ani* a, struct resources* r);
And 10 warnings in total for every usage of function pointers of the form:
src/init.c:17:16: warning: assignment to ‘void (*)(struct ani *)’ from incompatible pointer type ‘void (*)(struct ani *)’ [-Wincompatible-pointer-types]
17 | a->exclaim = exclaim;
| ^
src/init.c:18:13: warning: assignment to ‘void (*)(struct ani *, struct resources *)’ from incompatible pointer type ‘void (*)(struct ani *, struct resources *)’ [-Wincompatible-pointer-types]
18 | a->work = work;
Can someone please explain why such behaviour occurs and how I can avoid problems? It typically takes me an unfeasible amount of time to solve these errors and I still don't truly understand my mistake in the first place.
You've hit one of the odd corner cases of C scoping rules.
Informally, a tagged struct (or union, but I'm not going to repeat that over and over) springs into existence when it is named if no declaration for it is visible. "Springs into existence" means that it is considered declared in the current scope. Also, if a tagged struct was previously named in a scope and you then declare a struct with the same tag, the two structs are considered the same. Until a declaration for the struct is completed, the struct is considered an incomplete type, but a pointer to an incomplete type is a complete type, so you can declare a pointer to a tagged struct before you actually complete the definition of the struct.
Most of the time, that just works with minimal thought. But function prototypes are a bit special, because a function prototype is a scope, all by itself. (The scope lasts only until the end of the function declaration.)
When you put that together, you end up with the issue you're facing. You cannot use a pointer to a tagged struct in a function prototype unless the tagged struct was known before the function prototype appears. If it had been mentioned before, even in an outer scope, the tag is visible and therefore will be considered to be the same struct (even if it is still incomplete). But if the tag was not previously visible, a new struct type will be created within the prototype scope, which will not be visible after that scope ends (which is almost immediately).
Concretely, if you write the following:
extern struct animal * barnyard;
void exclaim(struct animal*);
then the two uses of struct animal refer to the same struct type, which will presumably be completed later (or in another translation unit).
But without the extern struct animal * barnyard; declaration, the struct animal named in the exclaim prototype is not previously visible, so thus is declared only in the prototype scope, so it is not the same type as some subsequent use of struct animal. Had you put the declarations in the opposite order, you would have seen a compiler warning (assuming you'd asked for compile warnings):
void exclaim(struct animal*);
extern struct animal * barnyard;
(On godbolt, bless it's heart)
A typedef declaration performs the same way as the extern declaration above; the fact that it is a type alias is not relevant. What's important is that the use of struct animal in the declaration causes the type to spring into existence, and you can subsequently use it freely in a prototype. That's the same reason that the function pointers inside your struct definitions are OK; the start of the struct definition was sufficient to cause the tag to be declared, so the prototype sees it.
In fact, any syntactic construction which contains a tagged struct (struct whatever) will serve the same purpose, because what matters is the effect of mentioning a tagged struct with no visible declaration. Above, I used extern global declarations as examples because they are lines which might appear in a header, but there are many other possibilities, including even the declaration of a function which returns a pointer to a struct (because the return type of a function declaration is not in the prototype scope).
See below for some additional comments about the edited question.
My personal preference is to always use typedefs as forward declarations of tags, and never use struct foo anywhere in my code other than the typedef and the subsequent definition:
typedef struct Animal Animal;
void exclaim(Animal*);
// ...
// Later or in a different header
struct Animal {
Animal* next;
void (*exclaim)(Animal *);
// etc.
};
Note that I always use the same identifier for the tag and the typedef. Why not? There's no confusion and tags have not been in the same namespace as other identifiers since C was premordial.
For me, a big advantage of this style is that it lets me separate implementation details; the public header only contains the typedef declarations (and prototypes which use that type) and only the implementation needs to contain the actual definitions (after first having included the public header).
Note: since this answer was written, the question was edited to add a more detailed code sample. For now, I'll just leave these additional notes here:
On the whole, you get better answers when you provide better information. Since I couldn't see your actual code, I did the best I could, which was to try to explain what is going on, leaving you to apply that to your actual code.
In the code you have now added to the question, there is a circular header dependency. These should be avoided; it's almost impossible to get them right. The circular dependency means that you don't control the order of inclusion, so a declaration in one header might not come before the use in another header. You no longer have a forward declaration, because, depending on the inclusion order, it might be a backward declaration.
To resolve the circular dependency, abstract out the shared components and put them in a new header file. Here, forward declarations of structs (using, for example, typedefs) are highly useful because they don't depend on anything used in the definition of the struct. A shared header might include only typedefs, or it might also include prototypes which don't require additional dependencies.
Also, avoid putting long lists of library includes in your header files; include only those headers actually necessary to define types actually used in the header.
I am studying C language and have recently learned how to write the OOP using C. Most part of it was not hard that much to understand for me except the name of structures type used to create new class.
My textbook used struct dummy_t for forward declaration and typedef struct {...} dummy_t for its definition. In my understanding, these are two different type because the former is struct dummy type and the later is struct type without a name tag but the sample code from the textbook worked well.
So I deliberately modified the sample code so that the difference in the names of structures will be much clearer. Below are the lines of code I tried.
//class.h
struct test_a;
struct test_a * test_init(void);
void test_print(struct test_a*);
//class.c
#include <stdio.h>
#include <stdlib.h>
typedef struct dummy{
int x;
int y;
} test_b;
test_b * test_init(void){
test_b * temp = (test_b *) malloc(sizeof(test_b));
temp->x = 10;
temp->y = 11;
return temp;
}
void test_print(test_b* obj){
printf("x: %d, y: %d\n", obj->x, obj->y);
}
//main.c
#include "class.h"
int main(void){
struct test_a * obj;
obj = test_init();
test_print(obj);
return 0;
}
// It printed "x: 10, y: 10"
As you can see, I used struct test_a for forward declaration and typedef struct dummy {...} test_b for definition.
I am wondering why I did not get the compile error and it worked.
I am wondering why I did not get the compile error
When you compile main.c the compiler is told via a forward declaration from class.h that there is a function with the signature struct test_a * test_init(void);
The compiler can't do anything other than just trusting that, i.e. no errors, no warnings can be issued.
When you compile class.c there is no forward declaration but only the function definition, i.e. no errors, no warnings.
It's always a good idea to include the .h file into the corresponding .c file. Had you had a #include "class.h" in class.c the compiler would have been able to detect the mismatch.
..and it worked
What happens is:
A pointer to test_b is assigned to a pointer to test_a variable
The variable is then passed as argument to a function expecting a pointer to test_b
So once you use the pointer it is used as it was created (i.e. as pointer to test_b). In between you just stored in a variable of another pointer type.
Is that ok? No
Storing a pointer to one type in a object defined for another pointer type is not ok. It's undefined behavior. In this case it "just happened to work". In real life it will "just happen to work" on most systems because most systems use the same pointer layout for all types. But according to the C standard it's undefined behavior.
It 'worked' because you did not include class.h in class.c. So the compiler can't see the implementation does not match the declaration.
The proper way is (but without the typedef for clarity):
// class.h
struct test_a;
struct test_a* test_init(void);
//class.c
#include "class.h"
struct test_a {
int x;
int y;
};
struct test_a* test_init(void)
{
...
}
The struct test_a in the header file makes the name test_a known to the compiler as being a struct. But as it does not now what is in the struct you can only use pointers to such a struct.
The members are defined in the implementation file and can only be used there.
If you want to use a typedef:
// header
typedef struct test_a_struct test_a;
test_a* test_init(void);
//implementation
struct test_a_struct {
int x;
int y;
};
test_a* test_init(void)
{
...
}
I'm a bit new to C and I'm having a bit of trouble with a project I'm currently working on. Essentially I have the following files: main.c, alarm.c, alarm.h
I have a struct declaration in alarm.c that looks like:
#define STRLEN 150;
struct alarmparams
{
char time[STRLEN];
char duration[STRLEN];
char snooze[STRLEN];
char port[STRLEN];
};
In main.c I have:
#include <stdio.h>
#include <string.h>
#include "alarm.h"
int main(int argc, char *argv[])
{
struct alarmparams params;
printf("%s, %s\n", params.time, params.duration);
}
And in alarm.h I have:
struct alarmparams;
Right now when I go to compile I get the following error:
error: storage size of ‘params’ isn’t known
I've looked through other posts regarding this error, so I have done a bit of research on this already. I've also tried some of the suggested solutions and it's either I get the exact same error or I got more on top of it. I'm at a lose as to how to fix this.
Is there something I'm missing? Did I declare something incorrectly?
In general should structs be declared in the header file or the c file? Or does it even matter? What's the different between:
struct foo {...};
and
typedef struct foo {...};
struct alarmparams;
is the declaration of an incomplete type. You can create a pointer to an object of this type but you cannot declare an object of this type or take its size until it has been completed. You have to make its complete declaration visible in main.c to declare an object of its type.
If you use the type in both alarm.c and main.c, just declare it in alarm.h and include alarm.h in main.c.
For you second question, the difference between:
struct foo {...};
and
typedef struct foo {...} foo_;
is in the latter case you also declare an alias foo_ for the type name struct foo.
You have to declare the structure in the header file alarm.h.
At the moment, when you include alarm.h, the code in main doesn't see the structure composition, all it sees is struct alarmparams;, so it doesn't know how long it is. How can you allocate space for something that you don't know how much space it takes?
typedef struct foo { ... }; is invalid: typedef expects you to provide an alias for a type. typedef struct foo { ... } foo_t; would be correct.
typedef is a storage class specifier, thus, you can think of it as any other regular declaration. Imagine you want an alias foo for the type bar: just declare a variable of type bar and call it foo. Now, prepend a typedef keyword behind, and you are done. Even complicated typedefs can be easily understood with this simple approach. Since struct foo { ... }; would be an invalid declaration for a variable (no name is provided), so is typedef struct foo { ... };.
In general, declare structures in the header file when you will reuse them in other source files. If you don't plan on doing so, declaring them on the .c file should be fine.
In addition to the other answers, the value of STRLEN must be known at compile time (it most likely is in this case, but just in case).
I'm a bit new to C and I'm having a bit of trouble with a project I'm currently working on. Essentially I have the following files: main.c, alarm.c, alarm.h
I have a struct declaration in alarm.c that looks like:
#define STRLEN 150;
struct alarmparams
{
char time[STRLEN];
char duration[STRLEN];
char snooze[STRLEN];
char port[STRLEN];
};
In main.c I have:
#include <stdio.h>
#include <string.h>
#include "alarm.h"
int main(int argc, char *argv[])
{
struct alarmparams params;
printf("%s, %s\n", params.time, params.duration);
}
And in alarm.h I have:
struct alarmparams;
Right now when I go to compile I get the following error:
error: storage size of ‘params’ isn’t known
I've looked through other posts regarding this error, so I have done a bit of research on this already. I've also tried some of the suggested solutions and it's either I get the exact same error or I got more on top of it. I'm at a lose as to how to fix this.
Is there something I'm missing? Did I declare something incorrectly?
In general should structs be declared in the header file or the c file? Or does it even matter? What's the different between:
struct foo {...};
and
typedef struct foo {...};
struct alarmparams;
is the declaration of an incomplete type. You can create a pointer to an object of this type but you cannot declare an object of this type or take its size until it has been completed. You have to make its complete declaration visible in main.c to declare an object of its type.
If you use the type in both alarm.c and main.c, just declare it in alarm.h and include alarm.h in main.c.
For you second question, the difference between:
struct foo {...};
and
typedef struct foo {...} foo_;
is in the latter case you also declare an alias foo_ for the type name struct foo.
You have to declare the structure in the header file alarm.h.
At the moment, when you include alarm.h, the code in main doesn't see the structure composition, all it sees is struct alarmparams;, so it doesn't know how long it is. How can you allocate space for something that you don't know how much space it takes?
typedef struct foo { ... }; is invalid: typedef expects you to provide an alias for a type. typedef struct foo { ... } foo_t; would be correct.
typedef is a storage class specifier, thus, you can think of it as any other regular declaration. Imagine you want an alias foo for the type bar: just declare a variable of type bar and call it foo. Now, prepend a typedef keyword behind, and you are done. Even complicated typedefs can be easily understood with this simple approach. Since struct foo { ... }; would be an invalid declaration for a variable (no name is provided), so is typedef struct foo { ... };.
In general, declare structures in the header file when you will reuse them in other source files. If you don't plan on doing so, declaring them on the .c file should be fine.
In addition to the other answers, the value of STRLEN must be known at compile time (it most likely is in this case, but just in case).
Isn't forward declaration, whether for structures or functions, supposed to do what forward declaration is expected to do, ie, to let us use the structure or function before they are defined? Why is the forward declaration of a structure not working in my code? And the main thing that just misses me, is forward declaration of structures of any use in C at all? When is it used? Can you please give me a small C program example to illustrate this?
My program gives the error error: storage size of 'x' isn't known|.
#include<stdio.h>
struct test;
int main(void)
{
struct test x;
printf("%zu",sizeof(x)); //Gives Error
//printf("%zu",sizeof(struct test));//This fails too
}
struct test
{
int a;
char b;
};
New Edit I tried to do what Carl Noum said,but even this is not working:
#include<stdio.h>
struct test;
void foo(struct test*);
int main(void)
{
struct test x={53,'x'},*ptr=&x;
foo(ptr);
}
void foo(struct test* p)
{
printf("%d,%c",p->a,p->b);
}
struct test
{
int a;
char b;
};
The compiler has to know the struct's layout when it compiles the main function.
A forward declaration is useful if you only have a pointer but not the actual type.
For example if you have a struct that contains a pointer to another struct
struct foo {
struct bar *b;
...
};
It is also essential if the bar also contain foo like
struct bar;
struct foo {
struct bar *b;
};
struct bar {
struct foo f;
};
In this case you have to have bar pre-declared.
A forward declaration usually means that you don't have to include .h file inside other .h file. This can speed up compilation significantly if the .h file is big.
Functions yes, structures no. struct test is an incomplete type where you use it.
A common use case for incomplete types is to declare an opaque type. In a header file, you declare:
struct test;
And then some API that uses struct test only via pointers:
int func1(struct test *);
struct test *func2(void);
In the accompanying implementation, you include the full declaration so that your functions know what to do with the structure:
struct test
{
int a;
char b;
};
void func1(struct test *t)
{
return t->a;
}
Edit:
Your new code doesn't do anything differently - you're still trying to operate on an incomplete type, and you still can't do that. In particular, this declaration:
struct test x = {53,'x'};
Can't work if struct test is an incomplete type. You can (generally) only use pointers to an incomplete type. In this case, that might mean creating a function that allocates and returns a pointer to a new structure, rather than trying to declare and initialize one on the stack.
Struct type declared by a forward declaration (i.e. an incomplete type) can be used only in a limited number of ways. Applying sizeof to such a truct type is not one of them. On top of that, you can't use incomplete types in object definitions and you cannot access data fields of incomplete struct types.
In other words, sizeof requires a complete type. Your forward-declared struct type is not a complete type. Operator -> also requres a complete type of the left-hand side. Object definition (like struct test x) also requires a complete type.