I'm building a linked list and I'm attempting to build a function to add a node, to test I pass through a name and size.
I think call it with my head but I get some strange error that I can't debug.
struct Test{
char name[_MAX_NAME];
int size;
struct Test *next;
};
typedef struct Test *node;
node AddNode(node head, char name, int size);
in my Main
node head = NULL; // is this problem?
head = AddNode(head,"Test Name",110);
Error C2040 'AddNode': 'node (node,char,int)' differs in levels of
indirection from 'int ()'
Consider the message “'node (node,char,int)' differs in levels of indirection from 'int ()'”. In this message, the int () is the type one gets non-C-standard compilers from the default declaration that is provided when you do not declare a function. That is, when you use AddNode before its declaration, it is automatically declared as int AddNode().
Then, later in your code when your declaration of AddNode appears, your declaration contrasts with the default declaration, and the compiler prints this message.
To fix this, put a declaration of AddNode before you use it. Such a declaration must appear in each source file where it is used. (Actually, the declaration must appear in the C translation unit, which means all the files that are included when you compile a source file. The translation unit includes header files that are included with #include. You must have a declaration of AddNode either in the source file itself or in a file it includes.)
Additionally, you declare AddNode as node AddNode(node head, char name, int size); but pass "Test Name" for the second parameter. As a function argument, "Test Name" acts as char *, not char, so you probably want to change the declaration to node AddNode(node head, char *name, int size);.
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 trying to pass a struct to a function residing in a separate file. When passing the struct as an argument, it throws errors.
Test.c
struct student{
int rollNumber;
unsigned char name[20];
int marks;
};
void func(struct student devanshu);
int main(){
struct student devanshu;
func(&devanshu);
printf("--------------------%d\n", devanshu.rollNumber);
printf("--------------------%d\n", devanshu.marks);
printf("--------------------%s\n", devanshu.name);
}
NewTest.c:
void func(struct student devanshu)
{
devanshu.rollNumber = 1;
devanshu.marks = 909;
strcpy(devanshu.name, "abc.xyz");
return;
}
And this is the output that I get:
In file included from test.c:6:0:
newtest.c:10:30: error: parameter 1 (‘devanshu’) has incomplete type
void func(struct student devanshu)
test.c: In function ‘main’:
test.c:23:7: error: incompatible type for argument 1 of ‘func’
func(&devanshu);
^
In file included from test.c:6:0:
newtest.c:10:6: note: expected ‘struct student’ but argument is of type ‘struct student *’
void func(struct student devanshu)
newtest.c:10:30: error: parameter 1 (‘devanshu’) has incomplete type
void func(struct student devanshu)
newtest.c:7:20: error: storage size of ‘devanshu’ isn’t known
struct student devanshu;
If I use the function in the same file i.e in test.c it does not throw any error and works just fine. But when keeping the functions in two different files, it gives me these errors.
Would be thankful if somebody could help me get through. Thanks in advance.
error: parameter 1 (‘devanshu’) has incomplete type
This means that the struct definition isn't visible to the file you use it inside. Unless this is intentional, you need to place the struct definition in a header file and include that by every .c file using the struct.
expected ‘struct student’ but argument is of type ‘struct student *’
You have written the functions incorrectly. It should be void func(struct student* devanshu); and inside the function you should access members with devanshu-> .... Otherwise you just pass a copy of the struct to the function and then change the local copy.
The errors are pretty self explanatory. Take this one:
test.c: In function ‘main’:
test.c:23:7: error: incompatible type for argument 1 of ‘func’
func(&devanshu);
It means you're passing something to func that has a different type to what you've told the compiler that func accepts. You've declared the function to take a struct student
void func(struct student devanshu);
but the function call is passing a pointer to struct student.
func(&devanshu);
The function call is correct as you want the function to have access to the struct you're passing and not a copy. So you'll need to change the function to take a struct student *.
The other errors are because you're not using an include file to store the definition of the struct.
Create a file called "student.h" (or whatever) and move the definition of the struct into it. And also the declaration of the function too.
struct student{
int rollNumber;
unsigned char name[20];
int marks;
};
void func(struct student *);
and at the top of both C files you put
#include "student.h"
which tells the compiler to copy the contents of that file into your C files when you're compiling. It means you have a consistent definition that can be shared by all the files that need it.
Ok, this will work: (Explanation below)
test.h: (New file!)
struct student{
int rollNumber;
char name[20];
int marks;
};
test.c:
#include <stdio.h>
#include <stdlib.h>
#include "test.h"
void func(struct student *devanshu);
int main(){
struct student devanshu;
func(&devanshu);
printf("--------------------%d\n", devanshu.rollNumber);
printf("--------------------%d\n", devanshu.marks);
printf("--------------------%s\n", devanshu.name);
}
NewTest.c:
#include <string.h>
#include "test.h"
void func(struct student *devanshu)
{
devanshu->rollNumber = 1;
devanshu->marks = 909;
strcpy(devanshu->name, "abc.xyz");
return;
}
This
unsigned char name[20];
will give you problems later on strcpy(). Change to just char.
This
void func(struct student devanshu);
is not wrong, but you fall into a trap. Structures in C are always passed by value (copy) of the entire struct. So, if you want func() to modify the original struct, you have to explicitly tell it so:
void func(struct student *devanshu);
Then, in func, you need to change the access syntax to using the -> operater insteadf of '.'
As you are using the struct student in both files, you need to move the declaration of the struct out into a header file. You could (as I did on the very first edit) also repeat the declaration because I was lazy, but the comments are 100% right: That is a very dangerous practice, so I changed that.
Consider a header file foo.h that contains:
struct wl_display;
struct wl_array * bar(struct wl_display *display);
And an implementation file foo.c that contains a complete definition of wl_display and an implementation of bar:
struct wl_display {
int baz;
};
struct wl_array * bar(struct wl_display *display) {
// ...
}
If I remove the forward declaration of struct wl_display, from foo.h, the gcc compiler will:
Emit a warning that the occurrence of struct wl_display *display in the parameter list is in block scope(warning: 'struct wl_display' declared inside parameter list and warning: its scope is only this definition or declaration, which is probably not what you want).
Emit an error: conflicting types for 'bar'
bar(struct wl_display *display).
However, if I then add a function that uses struct wl_display* as a return type, such that foo.h contains:
// struct wl_display;
struct wl_display * foo(void);
struct wl_array * bar(struct wl_display *display);
Everything compiles cleanly.
Why does the use of the struct wl_display* as a return type remove the need for the forward declaration? What is the "conflict" that causes error #2 above, since the parameter type is just a pointer, and the function signatures are identical?
Any usage of struct wl_display in file scope is a forward declaration of the type. So if the compiler sees it first, the usage in the parameter list refers to that type. If the declaration in the list is seen first, this declares a type that is only valid for the list and nowhere else.
The first reference to struct wl_display constitutes a declaration, albeit an incomplete one. In the case of a function return type, it is a top-level declaration. But inside an argument list, it is not. Instead, when declared inside an argument list, the declaration is scoped within the function, and goes out of scope after the function definition.
I am writing a program in which I have to pass an array of structure pointers to a function in main body as follows
struct node *vertices[20];
create_vertices (&vertices,20);
implementation of function is some thing like this
void create_vertices (struct node *vertices[20],int index)
{
}
in this I have to pass an array of structure pointers with index 20,
the declaration I did outside mains is as follows I
void create_vertices(struct node **,int);
However each time compiling the code gives me problem in these three lines only as
bfs.c:26:6: error: conflicting types for ‘create_vertices’
bfs.c:8:6: note: previous declaration of ‘create_vertices’ was here
bfs.c: In function ‘create_vertices’:
bfs.c:36:15: error: incompatible types when assigning to type ‘struct node’ from type ‘struct node *’
I am unable to understand how should I be doing this.
What I want to be able to do is:
Declare an array of structure pointers in main (which I already did).
Pass the address of array to function (here is where I goofed up).
Declare the correct prototype of function outside mains.
The code has to be on C and I am testing it on Linux.
Can some one point me?
The type of &vertices in the call create_vertices(&vertices, 20) is not what you think.
It is a pointer to an array of pointers to structs:
struct node *(*)[20]
and not
struct node **
Drop the & in the call and you'd be back in business.
The compilation (using GCC 4.7.0 on Mac OS X 10.7.4):
$ gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -c x3.c
x3.c: In function ‘func1’:
x3.c:16:9: warning: passing argument 1 of ‘create_vertices’ from incompatible pointer type [enabled by default]
x3.c:7:10: note: expected ‘struct node **’ but argument is of type ‘struct node * (*)[20]’
$
The code:
struct node { void *data; void *next; };
void make_node(struct node *item);
void func1(void);
void create_vertices(struct node **array, int arrsize);
void create_vertices(struct node *vertices[20], int index)
{
for (int i = 0; i < index; i++)
make_node(vertices[i]);
}
void func1(void)
{
struct node *vertices[20];
create_vertices(&vertices, 20);
}
Drop the & and the code compiles cleanly.
As you wrote: struct node *vertices[20]; declares an array of pointers to node. Now if you want to create a function that changes its elements, you should declare a function that takes this kind of array as an argument:
void create_vertices(struct node *arr[20], int size)
or since the size can be ommited in this case, it's better to declare it as:
void create_vertices(struct node *arr[], int size)
Note, that this function can be called like this: create_vertices(vertices, 20); which makes first argument of this function (arr) to point to first element of this array. You are able to change this array within this function and changes will be visible outside.
Let's say you have function void foo(struct node *ptr) that changes node that ptr points to. When you declare struct node *ptr; and pass to this function: foo(ptr);, it can change this node object and changes are visible outside, but it can't change the passed pointer ptr itself. When you need to change pointer within the function so that changes are visible outside, that's the situation when you pass an address of pointer to function taking pointer to pointer.
In the prototype of create_vertices, the first argument is a pointer to a pointer to a structure. In the definition the first argument is array of 20 pointers to a structure.
Both the prototype and the definition has to be the same.
I have this in a C file:
struct T
{
int foo;
};
the C file has an include to an h file with those lines:
typedef struct T T;
void listInsertFirst(T data, int key, LinkedList* ListToInsertTo);
the function listInsertFirst is the one I'm getting the warning on. How can I fix it?
As we've found out in the comments, the problem was that the definition of struct T occurred after the definition of T in the header. You really have things backwards here. The header should be defining all the types and function prototypes and your C files should be using them.
What you want to be doing instead is change the signature of your insert function to receive a pointer to your data and the size of the data. Then you can allocate some memory for the data, copy it and store it. You don't need a specific type, just declare it a void *.
void listInsertFirst(void *data, size_t data_size, int key, LinkedList* ListToInsertTo);
Then the caller would do something like this:
struct T { int foo; };
struct T x = { ... };
int someKey = ...;
LinkedList *someList = ...;
listInsertFirst(&x, sizeof x, someKey, someList);
When you include the header file, the compiler knows that T is a structure of unknown size and that listInsertFirst wants one as its first argument. But the compiler cannot arrange a call to listInsertFirst as it doesn't know how many bytes to push on the stack for the T data parameter, the size of T is only known inside the file where listInsertFirst is defined.
The best solution would be to change listInsertFirst to take a T* as its first argument so your header file would say this:
extern void listInsertFirst(T *data, int key, LinkedList* ListToInsertTo);
Then you get an opaque pointer for your T data type and, since all pointers are the same size (in the modern world at least), the compiler will know how to build the stack when calling listInsertFirst.
Are you sure it is the first parameter that is the problem? To be sure, try changing the parameter type from T to int temporarily. More than likely, the third parameter is actually the problem.
Many compilers don't point at the problem in these sorts of issues very well.
Try to move the structure definition to the h file, before the typedef.
Define struct T in header, not in .c file;
Choose different names for structure and typedef.