#include <stdio.h>
#include <stdlib.h>
void f(struct emp);
struct emp{
char name[20];
int age;
};
int main(){
struct emp e = {"nikunj", 23} ;
f(e);
return 0;
}
void f(struct emp e){
printf("%s %d\n", e.name, e.age);
}
Running the above code gives the following errors
nikunjbanka#ubuntu:~$ gcc hello2.c -o main.out
hello2.c:3:15: warning: ‘struct emp’ declared inside parameter list [enabled by default]
hello2.c:3:15: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
hello2.c: In function ‘main’:
hello2.c:10:2: error: type of formal parameter 1 is incomplete
hello2.c: At top level:
hello2.c:14:6: error: conflicting types for ‘f’
hello2.c:3:6: note: previous declaration of ‘f’ was here
But the book test your C skills says that the order of prototype declaration and structure declaration in the program does not matter. I want to ask whether the order matters or not?
Yes the order absolutely does matter.
Re-order your code such that the definition of struct emp appears before the function prototype for f.
#include <stdio.h>
#include <stdlib.h>
struct emp{
char name[20];
int age;
};
void f(struct emp);
...
gcc is actually trying to tell you that you did things in the wrong order, however the compiler messages are a little bit confusing if this is your first time reading through them.
These two warnings:
hello2.c:3:15: warning: ‘struct emp’ declared inside parameter list [enabled by default]
hello2.c:3:15: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
indicate that the type of 'struct emp' was not known at the time gcc compiled line 3 of your file. The compiler will typically try to infer a default type & size for the unknown struct emp and almost always guesses incorrectly because it has no idea how you will eventually declare struct emp.
This error:
hello2.c:10:2: error: type of formal parameter 1 is incomplete
indicates that you are trying to call function 'f' with an actual parameter type that is different than the formal parameter type that gcc (incorrectly) inferred when it compiled line 3 of the file.
This error and associated note:
hello2.c:14:6: error: conflicting types for ‘f’
hello2.c:3:6: note: previous declaration of ‘f’ was here
indicates that the formal parameter type on line 14 (which is now known to be the type struct emp you declared on lines 4 through 7) did not match the formal parameter type that gcc (again incorrectly) inferred on line 3.
Bottom line: define all of your types before the prototypes that refer to them, and you should be fine.
You may also find your code is more readable if you use
typedef struct {
char name[20];
int age;
} emp_t;
And then you can use emp_t rather than struct emp throughout the subsequent code.
There's another option - this change will fix it too:
#include <stdio.h>
#include <stdlib.h>
struct emp; /* <--- add this line */
void f(struct emp); /* <-- now this refers to that */
struct emp{ /* <-- and this defines the same thing */
char name[20]; /* and you didn't need to move things around. */
int age;
};
In a complex project it's not always easy to resolve all the ordering issues, this can be helpful.
Note that when f is actually f(struct emp*) --not f(struct emp)- then you may be able to define f() without including a definition of the struct layout.
This is because the compiler can work with pointers to structs that are named, but not defined - provided you only do certain things to them (store them, return them, pass them to other functions; compare them to NULL, or to other pointers to the same thing... cast them to other pointer types...) - but you can't do pointer arithmetic, or access members (obviously) or ask for sizeof(*p) if p is a pointer to an unspecified struct. The compiler will let you know :-)
Related
I've read this thread and searched around for more information but most people just say "don't use typedefs like this." This way of doing things is appealing to me and I am also trying to learn new things, so I want to stick with this.
I'm using gcc version 9.2.1
Here is a minimum reproducible example of what I'm doing:
#define TABLE_SZ 10
typedef int vec_t[3];
typedef struct {
vec_t table_one[TABLE_SZ];
} tables;
void foo(vec_t * foo_vec) {
(*foo_vec)[0] = 0;
}
void bar (tables bar_table, vec_t bar_vec) {
foo(&(bar_table.table_one[0]));
foo(&bar_vec);
}
int main() {
vec_t vector;
foo(&vector);
}
/home/happy/CLionProjects/os_2019_p5/tests/test_array_typedef_ops.c: In function ‘bar’:
/home/happy/CLionProjects/os_2019_p5/tests/test_array_typedef_ops.c:18:7: warning: passing argument 1 of ‘foo’ from incompatible pointer type [-Wincompatible-pointer-types]
18 | foo(&bar_vec);
| ^~~~~~~~
| |
| int **
/home/happy/CLionProjects/os_2019_p5/tests/test_array_typedef_ops.c:12:18: note: expected ‘int (*)[3]’ but argument is of type ‘int **’
12 | void foo(vec_t * foo_vec) {
| ~~~~~~~~^~~~~~~
I assume this has something to do with "pointer decay", I guess bar converting bar_vec to int **?
Specifically, why is the type of &(bar_table.table_one[0]) int (*)[3] when bar_vec is int ** ?
I obviously don't want to supress all incompatible pointer type warnings in gcc.
Casting the pointer seems like a kludge.
I want to keep the typedef. I don't want to hide it in a struct.
Is there a compiler flag or other solution to tell the compiler to treat this situation as I expect it to?
Is there more information on this I should be aware of?
Thank you.
p.s. does stack overflow have pretty printing for compiler output?
void bar (tables bar_table, vec_t bar_vec) is bad in many ways:
You pass the struct by value which very ineffective and can't get optimized by the compiler if the function is in a different translation unit.
The typedef vec_t doesn't prevent your array type from getting adjusted ("decay") upon getting passed as parameter, so vec_t bar_vec is equivalent to int*. And this array is therefore not getting passed by value, just its address.
The reason for the compiler error is however this: foo(&bar_vec);. You pass a pointer to the int* you have hidden beneath the typedef, meaning that you pass an int**. The function however, expects a vec_t *, meaning an array pointer of type int(*)[3]. This is what the compiler is telling you.
There is no compiler flag to solve this, because the code doesn't make any sense. Solve this by getting rid of the typedef, then rewrite the code.
I'm trying to pass a struct by reference but no matter what I do I'm running into errors. I think I have the prototyping and declaration and the pointers all screwed up.
This is for an Arduino project of mine. The code works fine on the Arduino compiler but doesn't compile on Pelles C compiler.
#include <stdio.h>
#include <string.h>
#include <stdint.h>
void Fault_Bits_To_Flags(uint8_t Master_Fault_Byte, struct Fault_Flag_Struct *Fault_Flag);
struct Fault_Flag_Struct {
char Fault_Name[30];
uint8_t Fault_State;
};
struct Fault_Flag_Struct Fault_Flag [7];
int main(void) {
uint8_t Master_Fault_Byte = 181;
strcpy(Fault_Flag[0].Fault_Name, "fault 0");
Fault_Flag[0].Fault_State = 1;
strcpy(Fault_Flag[1]....
strcpy(Fault_Flag[2]....
strcpy(Fault_Flag[3]....
strcpy(Fault_Flag[4]....
Fault_Bits_To_Flags( Master_Fault_Byte, *Fault_Flag);
return 0;
}
//Puts 8 bits from single byte into 8 separate bytes (flags)//
void Fault_Bits_To_Flags(uint8_t Master_Fault_Byte, struct Fault_Flag_Struct *Fault_Flag) {
for ( int i = 0; i < 8; i++ )
{
Fault_Flag[i].Fault_State = (Master_Fault_Byte >> i) & 1;
}
}
error #2140: Type error in argument 2 to 'Fault_Bits_To_Flags';
expected '(incomplete) struct Fault_Flag_Struct *' but found 'struct
Fault_Flag_Struct'.
error #2120: Redeclaration of 'Fault_Bits_To_Flags', previously
declared at Reference.c(4); expected 'void function(unsigned char,
(incomplete) struct Fault_Flag_Struct *)' but found 'void
function(unsigned char, struct Fault_Flag_Struct )'.
Error code: 1 *
The scope of a parameter declaration in the list of parameters of a function prototype terminates at the end of the function declarator. Opposite to C++ there is no such a notion as the elaborated type specifier in C.
From the C Standard (6.2.1 Scopes of identifiers)
... If the declarator or type specifier that declares the identifier appears
within the list of parameter declarations in a
function prototype (not part of a function definition), the identifier
has function prototype scope, which terminates at the end of the
function declarator
So the type specifier struct Fault_Flag_Struct used in the function prototype
void Fault_Bits_To_Flags(uint8_t Master_Fault_Byte, struct
Fault_Flag_Struct *Fault_Flag);
denotes a different entity compared with the declaration that follows the function prototype
struct Fault_Flag_Struct {
char Fault_Name[30];
uint8_t Fault_State;
};
So you have to exchange the placements of the declarations.
Also this call
Fault_Bits_To_Flags( Master_Fault_Byte, *Fault_Flag);
is invalid because the type of the expression *Fault_Flag is struct Fault_Flag_Struct while the function expects the type struct Fault_Flag_Struct *. That is instead of a pointer to an object of the type struct Fault_Flag_Struct you are passing the object itself.
Scope and Structure Types
There are two problems in the code shown.
The first is because C has some odd rules about structure definitions. One rule, in C 2018 6.7.2.3 4, is that structure declarations with the same tag (the name after struct) declare the same type (a structure type with that name) only if they have the same scope:
All declarations of structure, union, or enumerated types that have the same scope and use the same tag declare the same type.…
When you declare a structure inside a function declaration, like this:
void foo(struct X *p);
Then the scope of X is function prototype scope. Per 6.2.1 4, this scope ends at the end of the function declaration. Then, when you later define the structure, as with:
struct X { int q; }
it is in a different scope, and, per the rule above, the struct X in the function declaration is not the same type as the struct X in the later definition. One way to fix this is to move the structure definition prior to the function declaration. It also suffices merely to declare the structure tag prior to the function declaration, as with:
struct X;
void foo(struct X *p);
To fully understand what is happening here, we should consider two other issues. One issue is that we could have struct X in two different translation units (different source files compiled separately), and calling a function defined with a struct X * parameter in one unit from another unit that defines struct X is allowed. This is because that, although the two struct X types in the two translations units are different, they are compatible. 6.2.7 1 says:
… Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if…
Oddly, this rule only applies to structures declared in separate translation units. If we defined void foo(struct X *p { … } prior to defining struct X in one translation unit, they are different and incompatible types, but, if we define them in separate units, they are compatible types!
The second issue is how can this code work when the structure declarations have separate scopes:
struct X;
void foo(struct X *p);
The first struct X has file scope (per 6.2.1 4), and the second struct X has function prototype scope. The rule in 6.7.2.3 4 only applies if the declarations have the same scope, so it does not say these declare the same struct X. Instead, there is another rule, in 6.7.2.3 9:
If a type specifier of the form struct-or-union identifier or enum identifier occurs other than as part of one of the above forms, and a declaration of the identifier as a tag is visible, then it specifies the same type as that other declaration, and does not redeclare the tag.
(The “above forms” are definitions or stand-alone declarations.) This causes the struct X in the function declaration after a prior file-scope struct X to specify the same type.
Error in Argument
The second error is in the second argument passed to the function in this statement:
Fault_Bits_To_Flags( Master_Fault_Byte, *Fault_Flag);
Fault_Flag is an array, so *Fault_Flag is the first element of the array. This is a structure, not a pointer. To pass a pointer to the first element of the array, use:
Fault_Bits_To_Flags( Master_Fault_Byte, Fault_Flag);
I just found a quirk in C that I find really confusing. In C it's possible to use a pointer to a struct before it has been declared. This is a very useful feature that makes sense because the declaration is irrelevant when you're just dealing with a pointer to it. I just found one corner case where this is (surprisingly) not true, though, and I can't really explain why. To me it looks like a mistake in the language design.
Take this code:
#include <stdio.h>
#include <stdlib.h>
typedef void (*a)(struct lol* etc);
void a2(struct lol* etc) {
}
int main(void) {
return 0;
}
Gives:
foo.c:6:26: warning: ‘struct lol’ declared inside parameter list [enabled by default]
foo.c:6:26: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
foo.c:8:16: warning: ‘struct lol’ declared inside parameter list [enabled by default]
To remove this problem we can simply do this:
#include <stdio.h>
#include <stdlib.h>
struct lol* wut;
typedef void (*a)(struct lol* etc);
void a2(struct lol* etc) {
}
int main(void) {
return 0;
}
The unexplainable problem is now gone for an unexplainable reason. Why?
Note that this question is about the behavior of language C (or possible the compiler behavior of gcc and clang) and not the specific example I pasted.
EDIT:
I won't accept "the order of declaration is important" as an answer unless you also explain why C would warn about using a struct pointer for the first time in a function argument list but allow it in any other context. Why would that possibly be a problem?
To understand why the compiler complains, you need to know two things about C "struct"s:
they are created (as a declared, but not yet defined, type) as soon as you name them, so the very first occurrence of struct lol creates a declaration
they obey the same "declaration scope" rules as ordinary variables
(struct lol { declares and then begins defining the structure, it's struct lol; or struct lol * or something else that does not have the open-brace that stops after the "declare" step.)
A struct type that is declared but not yet defined is an instance of what C calls an "incomplete type". You are allowed to use pointers to incomplete types, as long as you do not attempt to follow the pointer:
struct lol *global_p;
void f(void) {
use0(global_p); /* this is OK */
use1(*global_p); /* this is an error */
use2(global_p->field); /* and so is this */
}
You have to complete the type in order to "follow the pointer", in other words.
In any case, though, consider function declarations with ordinary int parameters:
int imin2(int a, int b); /* returns a or b, whichever is smaller */
int isum2(int a, int b); /* returns a + b */
Variables named a and b here are declared inside the parentheses, but those declarations need to get out of the way so that the the next function declaration does not complain about them being re-declared.
The same thing happens with struct tag-names:
void gronk(struct sttag *p);
The struct sttag declares a structure, and then the declaration is swept away, just like the ones for a and b. But that creates a big problem: the tag is gone and now you can't name the structure type ever again! If you write:
struct sttag { int field1; char *field2; };
that defines a new and different struct sttag, just like:
void somefunc(int x) { int y; ... }
int x, y;
defines a new and different x and y at the file-level scope, different from the ones in somefunc.
Fortunately, if you declare (or even define) the struct before you write the function declaration, the prototype-level declaration "refers back" to the outer-scope declaration:
struct sttag;
void gronk(struct sttag *p);
Now both struct sttags are "the same" struct sttag, so when you complete struct sttag later, you're completing the one inside the prototype for gronk too.
Re the question edit: it would certainly have been possible to define the action of struct, union, and enum tags differently, making them "bubble out" of prototypes to their enclosing scopes. That would make the issue go away. But it wasn't defined that way. Since it was the ANSI C89 committee that invented (or stole, really, from then-C++) prototypes, you can blame it on them. :-)
The compiler is warning you about a forward declaration of struct lol. C allows you to do this:
struct lol; /* forward declaration, the size and members of
struct lol are unknown */
This is most used when defining self-referencing structs, but it is also useful when defining private structs that are never defined in the header. Because of this latter use case, it is allowed to declare functions that receive or return pointers to incomplete structs:
void foo(struct lol *x);
However, just using an undeclared struct in a function declaration, as you did, will be interpreted as a local incomplete declaration of struct lol whose scope is constrainted to the function. This interpretation is mandated by the C standard, but it is not useful (there is no way to construct the struct lol to pass to the function) and is almost certainly not what the programmer intended, so the compiler warns.
This is because, in the first example, the struct is previously undefined and so the compiler tries to treat this first reference to that struct as a definition.
In general, C is a language where the order of your declarations matters. Everything you use should be properly declared in advance in some capacity, so that the compiler can reason about it when it's referenced in other context.
This is not a bug or a mistake in the design of the language. Rather, it's a choice that I believe was made to simplify the implementations of the first C compilers. Forward declarations allow a compiler to translate the source code serially in one pass (as long as some information such as sizes and offsets is known). If this weren't the case, the compiler would have be able to go back and forth in the program whenever it meets an unrecognized identifier, requiring its code emission loop to be much more complex.
I see this same warning before. My fix is to include the proper header file which contains the definition of the struct.
In addition to other answers, I would like to post a code example, which makes the problem more obvious. Please consider the following:
int testFunc(struct SomeStruct {int a; int b;} param1) // gcc: warning ...
{
return param1.a + param1.b;
}
int main(void)
{
struct SomeStruct params; // gcc: error: storage size of 'params' isn't known
params.a = 25;
params.b = 15;
return testFunc(params);
}
As you can see, the function declaration of testFunc is considered a valid C code (tested with GCC 12, Clang 15 and MSVC 19.32). However, you can't really use it because SomeStruct is only valid within the scope of the function, which is what compiler warns you about.
I've stumbled on this myself when working on my own C parser as the allowance of such syntax makes parser development easier as you can reuse the same implementation to parse struct declaration inside function parameter lists. It is surprising, however, that such bizarre syntax is still considered valid nowadays (as of C17) and instead of error you just get a warning.
Lookout for typos and DOUBLE CHECK your line numbers! I concat all my source files before compiling, so the line numbers from the source I am working in are meaningless. I have to take extra time to open up the concatted payload and examine it. So usually I don't and I just assume I know what line I am looking at from the console output message.
Example:
GCC Says:
EXAMPLE.C11:27:1: error: 'struct THIS_STRUCT_IS_OK' declared inside
parameter list [-Werror] ){
#include <stdio.h> //:for: printf(...)
struct THIS_STRUCT_IS_OKAY{
int whatever;
};
int LookingAtThisFunction(
struct THIS_STRUCT_IS_OKAY* arg
){
//: (Because you are not checking line numbers, you )
//: (assume you are looking here. But you are not. )
//: (Maybe you are concatenating all of your source )
//: (files together before compiling and line numbers )
//: (don't correspond to the original source and you )
//: (didn't examine your concatted source code payload?)
return( arg -> whatever );
}
//:You are not looking here because this is later in the
//:file, so the compiler would be complaining about the
//:FIRST usage of the struct, not the second one, you assume.
//:And you would be correct, if there wasn't a typo.
void WhereYouAreNotLooking(
struct THIS_STRUCT_IS_OK* arg
){
LookingAtThisFunction( arg );
}
int main( void ){
}
In summary: If you know what the error message means. And you swear to god
the compiler is broken because you already checked that...
1. Look for typos.
2. Make sure you are really looking at the correct line number.
I get that this is kinda stupid. But it had been scratching my head for
half an hour. So hopefully it helps someone who's already looked at the
obvious solutions.
The below program is having two structures. I don't understand how I can pass value from one structure variable to another structure variable while using pointers
#include <stdio.h>
typedef struct {
int c;
char d;
}bob;
typedef struct {
int c;
char d;
}anna;
//expecting 'bob' type variable
void fun(bob *var2)
{
printf("var2->c=%d\n",var2->c);
printf("var2->d=%c\n",var2->d);
}
int main()
{
anna var1;
var1.c=2;
var1.d='c';
fun(&var1);//passing 'anna' type pointer
return 0;
}
...but if I change the program to pass values using normal variables, it gives compilation error.
#include <stdio.h>
typedef struct {
int c;
char d;
}bob;
typedef struct {
int c;
char d;
}anna;
//expecting a variable of type 'bob'
void fun(bob var2)
{
printf("var2.c=%d\n",var2.c);
printf("var2.d=%c\n",var2.d);
}
int main()
{
anna var1;
var1.c=2;
var1.d='c';
fun(var1);//passing a variable of type 'anna'
return 0;
}
What is the logic behind this?
First of all, the first version, does warn you. with proper compiler options enabled, you'll see
source_file.c: In function ‘main’:
source_file.c:30:5: warning: passing argument 1 of ‘fun’ from incompatible pointer type
fun(&var1);//passing 'anna' type pointer
^
source_file.c:16:6: note: expected ‘struct bob *’ but argument is of type ‘struct anna *’
void fun(bob *var2)
That said, in the first version of the code
//expecting 'bob' type variable
is wrong!! Its ought to be (follow emphasis)
//expecting a pointer to 'bob' type variable
As per C rules, a pointer to a type can be converted to another type, but the result is not always defined. So, the first version of the code compiler (with warnings) and runs.
OTOH, in the second case, anna and bob are different types, so the inter-change is not possible while passing the argument and receiving the parameter. To the compiler, they are different types and compiler behaves accordingly.
Answer for beginner/intermediately experienced:
Any two structure types in C with different type names are not compatible types. No matter if they happen to have the same member variables. Similarly, pointers to different structure types are not compatible. So your types "bob" and "anna" are not compatible, and using them like you attempt is formally not safe nor well-defined.
Simply refrain from doing things like this, you will end up writing subtle bugs.
Answer for veterans:
Despite the type compatibility rules mentioned above, C (but not C++) allows some tricks to let you use one memory region in several different ways, no matter the type of the variables stored there. This is known as "type punning". Most often type punning is done through union, for example:
typedef struct
{
bob b;
anna a;
} bobanna;
If you would use a pointer to a type like the one above, you are actually allowed to assume that either of the two types can be used, but only because in this case, all the involved struct/union members contain (recursively) the very same types. For example, code like this is fine:
void fun (bobanna *var)
{
bob* b = var.b;
b.c = something;
}
bobanna ba = {.anna.c = 1 };
fun(&ba);
Please note that type punning is an advanced topic. It is very easy to do things like this in the wrong way - I would not recommend to even consider the above trick if you don't already know about pointer aliasing and the strict aliasing rule.
I have a simple header file with the following code:
#include < stdio.h >
#include < pthread.h >
void init(struct prodcons * b);
void put(struct prodcons * b, int data);
int get(struct prodcons * b);
void * producer(void * data);
void * consumer(void * data);
when I compile the terminal give this four warnings:
producer_consumer.h:4:18: aviso: ‘struct prodcons’ declared inside parameter list [enabled by default]
producer_consumer.h:4:18: aviso: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
producer_consumer.h:6:17: aviso: ‘struct prodcons’ declared inside parameter list [enabled by default]
producer_consumer.h:8:16: aviso: ‘struct prodcons’ declared inside parameter list [enabled by default]
You need to declare struct prodcons somewhere. Right now there's no declaration for it, so the compiler is inferring it.
Presumably you have a declaration for this in another file -- if it's in another header, add an #include directive for it to the top of this .h file, before all the functions that use it.
The compiler complains about the missing declaration of "struct prodcons". You have to include a header file that actually gives a declaration of that struct, or you have to insert a forward declaration of that struct, like just writing:
struct prodcons;
struct prodcons has not been defined anywhere. You need to define it before those prototypes, or #include a header file that defines it.
Since the parameter list is the first time the compiler has seen struct prodcons, it assumes that you are declaring it there (which makes no sense).