In the following program I try to pass a structure to a function. But I get errors,and I do not understand why. What mistake have I made in this program ?
I am using gcc for compiling this c program.
#include <stdio.h>
struct tester {
int x;
int *ptr;
};
void function(tester t);
int main() {
tester t;
t.x = 10;
t.ptr = & t.x;
function(t);
}
void function(tester t) {
printf("%d\n%p\n",t.x,t.ptr);
}
Errors :
gcc tester.c -o tester
tester.c:8:15: error: unknown type name ‘tester’
tester.c: In function ‘main’:
tester.c:12:2: error: unknown type name ‘tester’
tester.c:13:3: error: request for member ‘x’ in something not a structure or union
tester.c:14:3: error: request for member ‘ptr’ in something not a structure or union
tester.c:14:13: error: request for member ‘x’ in something not a structure or union
tester.c: At top level:
tester.c:18:15: error: unknown type name ‘tester’
NOTE : If I replace printf with cout and stdio with iostream and name the extension to .cpp (!), I get no errors. Why is that ? No wonder I compile it using g++
If you don't typedef the struct you must specify struct in front of the struct name while declaring it like so:
struct tester t;
Either you do that or you do the following:
typedef struct {
int x;
int *ptr;
}tester;
Update
Below is a quote from Adam Rosenfield from the following post Difference between 'struct' and 'typedef struct' in C++?:
In C++, all struct/union/enum/class declarations act like they are implicitly typedef'ed, as long as the name is not hidden by another declaration with the same name.
your struct isn't named. either use struct tester t; or usa a typedef
The thing is you're trying to compile with gcc, which is a "c language" compiler and you're following C++ style of code.
It is possible to create a struct variable by just structname variablename;
but in c++, you explicitly have to tell the compiler it is a struct like
struct structname variablename;
Just do that and you'll be fine, otherwise you can use a typedef which is basically you tell the compiler form now on you are going to call struct tester to only tester, which will suit you more since you only have to only a minor change.
Related
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 have declared a typedef struct on header files as follows:
myheader.h
typedef struct mystruct mystruct;
myheader.c
typedef struct mystruct{
double *ptr1;
double *ptr2;
int *ptr3;
mystruct *ptr4;
mystruct *ptr5;
}mystruct;
program.c
#include "myheader.h"
int main()
{
mystruct *A = (mystruct *)malloc(sizeof(mystruct));
}
when i try to compile using:
gcc -o myprogram myprogram.c myheader.c
i get the following error:
error: invalid application of ‘sizeof’ to incomplete type ‘mystruct’ {aka ‘struct mystruct’}
mystruct * A = (mystruct *)malloc(sizeof(mystruct));
Is there something wrong with my code or am I compiling in the wrong way?
As #someprogrammerdude has already pointed out in his comment about translation units: when the compiler compiles main.c it has only knowledge about main.c and the included headers. So all it knows is that that there is a struct typedefed as mystruct but it knows nothing about its content and thus cannot determine ts size either, so you cannot use sizeof(). For the same reason you couldn't access any struct members, int *p = mystruct->ptr3; or mystruct->ptr1 = &mydouble; wouldn't compile as well.
Nevertheless that design is quite common. Let's assume you want to encapsulate every access to mystruct in an OO like manner. Then you have a source, say mystruct.c where you actually define the structure (like you did in myheader.c) and provide all neccessary getter and setter functions (including an allocation function). Then in every other source you could pass struct pointers any way you like but for everything else you have to use the designated functions.
The advantage of that approach is that in the future you're free to modify the struct whithout having to recompile every source that uses it.
I am creating an interface structure
typedef struct Circular_Buffer_Interface_t * Circular_Buffer_Interface;
typedef struct Circular_Buffer_Interface_t {
U8 (*Put)(Circular_Buffer, void*);
U8 (*Get)(Circular_Buffer, void*);
U8 (*Reset)(Circular_Buffer);
BOOL (*isFull)(Circular_Buffer);
BOOL (*isEmpty)(Circular_Buffer);
} Circular_Buffer_Interface_t;
typedef struct Circular_Buffer_t * Circular_Buffer;
typedef struct Circular_Buffer_t {
Circular_Buffer_Interface Interface;
} Circular_Buffer_t;
My question is when I try to compile why using void* as a function argument it throws a syntax error.
if I use a typedef
typedef void* VoidPtr
and then use
typedef void* VoidPtr;
typedef struct Circular_Buffer_Interface_t {
U8 (*Put)(Circular_Buffer, VoidPtr);
U8 (*Get)(Circular_Buffer, VoidPtr);
U8 (*Reset)(Circular_Buffer);
BOOL (*isFull)(Circular_Buffer);
BOOL (*isEmpty)(Circular_Buffer);
} Circular_Buffer_Interface_t;
everything complies just fine.
Does anyone have a clue while this is happening?
Thanks in advance.
This member declaration
U8 (*Put)(Circular_Buffer, VoidPtr);
will work fine if neither Circular_Buffer nor VoidPtr are defined with typedef at that point in the source code. (U8 must be defined, though.) That's because it will be accepted as a K&R-style function declaration which specifies the names of the parameters but not their types. (That is, Put will be declared as a pointer to a function taking two parameters of unspecified type.)
It will also work if both Circular_Buffer and VoidPtr are defined as typedefs, in which case it will be treated as a normal standard C declaration.
If you compile with -Wall, the first case will probably produce a warning. -Wall is always recommended.
It should fail to compile if only one of the two identifiers is declared as a typedef, so I don't know how it works in the case where typedef void* VoidPtr comes before the member declaration, and typedef struct ... Circular_Buffer comes afterwards. Perhaps that's an obscure feature of an old version of gcc. (Once the compiler decides it is a K&R function declaration, the actual parameter names can be ignored unless the it is a function definition, and in the context in which the line appears, it cannot be a function definition.)
The first declaration, with the void *, seems perfectly valid C. I added some code to make this a complete program:
#include <stdio.h>
typedef int U8;
typedef int BOOL;
typedef int Circular_Buffer;
typedef struct Circular_Buffer_Interface_t {
U8 (*Put)(Circular_Buffer, void*);
U8 (*Get)(Circular_Buffer, void*);
U8 (*Reset)(Circular_Buffer);
BOOL (*isFull)(Circular_Buffer);
BOOL (*isEmpty)(Circular_Buffer);
} Circular_Buffer_Interface_t;
int main() {
puts("hello");
}
This program compiles successfully and without warning with GNU C version 5.2 on MacOSX:
> gcc-5 -std=c99 -Wall x.c
> ./a.out
hello
The same works with the Apple version of clang. Thus I suspect that the problem is with your C compiler, rather than with your code.
I have set-up structs like so in a C program:
typedef struct header block_header;
struct header {
size_t size;
block_header *next_pointer;
block_header *prev_pointer;
};
However, when I run any expression like the following:
int myinit()
{
block_header *p = init_heap_segment(BLOCK_HEAD_SIZE);
// etc etc
}
It gives me several errors for each function that it is declared in:
allocator.c: In function ‘myinit’:
allocator.c:37:38: error: ‘header’ undeclared (first use in this function)
allocator.c:37:38: note: each undeclared identifier is reported only once for each function it appears in
allocator.c: In function ‘function’:
allocator.c:67:2: error: unknown type name ‘header’
What is the problem with the way that it is set-up? How do I make these errors go away?
EDIT: Definition of:
#define BLOCK_HEAD_SIZE (ALIGN(sizeof(header)))
This is your problem
#define BLOCK_HEAD_SIZE (ALIGN(sizeof(header)))
There's no such type as header in your program, which is what the compiler is telling you. You have defined type struct header and you have defined a typedef name block_header for it. So choose whichever you prefer: either sizeof(struct header) or sizeof(block_header). But not sizeof(header).
In C++ language defining a struct header type would also introduce typename header into the program. But not in C. In C the type defined by struct header is called struct header - two words. It cannot be shortened to a mere header.
In your program, there is no such type called header. But you are using
#define BLOCK_HEAD_SIZE (ALIGN(sizeof(header))) // problem
It should be-
#define BLOCK_HEAD_SIZE (ALIGN(sizeof(struct header)))
or
#define BLOCK_HEAD_SIZE (ALIGN(sizeof(block_header)))
Whenever you are calculating size like this, make sure that you are using correct parameters!
Why not just do:
typedef struct block_header {
size_t size;
block_header *next_pointer;
block_header *prev_pointer;
}header;
and with that you can do:
header *p = init_heap_segment(BLOCK_HEAD_SIZE);
with a new declaration for init_heap_segment() where it returns 'header *' instead of 'struct block_header *'. Just much cleaner.
I know this is a very basic problem, but I cannot move forward without it and its not clearly explained elsewhere.
Why is this programming giving me so many errors of undeclared identifier? I have declared it, though.
These are the error i am getting.
Error 2 error C2143: syntax error : missing ';' before 'type'
Error 3 error C2065: 'ptr' : undeclared identifier
Error 4 error C2065: 'contactInfo' : undeclared identifier
Error 5 error C2059: syntax error : ')'
Error 15 error C2223: left of '->number' must point to struct/union
and more...
#include<stdio.h>
#include<stdlib.h>
typedef struct contactInfo
{
int number;
char id;
}ContactInfo;
void main()
{
char ch;
printf("Do you want to dynamically etc");
scanf("%c",&ch);
fflush(stdin);
struct contactInfo nom,*ptr;
ptr=(contactInfo*)malloc(2*sizeof(contactInfo));
nom.id='c';
nom.number=12;
ptr->id=nom.id;
ptr->number=nom.number;
printf("Number -> %d\n ID -> %c\n",ptr->number,ptr->id);
}
typedef struct contactInfo
{
int number;
char id;
}ContactInfo;
This code defines 2 things:
a type named ContactInfo
a struct named contactInfo
Notice the difference of the c and C!
In your code you are using a mixed combination of both, which is allowed (although confusing IMHO).
If you use the struct variant you need to explicitly use struct contactInfo. For the other variant (ContactInfo) you must to omit the struct part as it is part of the type definition alteady.
So be careful with both different definitions of your structure. Best would be to only use either one of the variants.
I do not have Visual Studio at hand, but the following (corrected) code compiles with gcc properly without any warnings:
#include<stdlib.h>
typedef struct contactInfo
{
int number;
char id;
}ContactInfo;
void main()
{
ContactInfo nom,*ptr;
ptr=malloc(2*sizeof(ContactInfo));
}
(I left out the not so interesting/unmodified parts of the code)
This:
ptr=(contactInfo*)malloc(2*sizeof(contactInfo));
is wrong, there's no type called contactInfo.
There's a struct contactInfo, which is typedef:d as ContactInfo. C is case-sensitive (and you must include the struct unlike how it works in C++).
Also note that the quoted line is better written as:
ptr = malloc(2 * sizeof *ptr);
Since casting the return value of malloc() is a bad idea in C, I removed the cast. Also, repeating the type is a bad idea since it makes the risk of introducing error greater, so I removed that as well.
Note that sizeof *ptr means "the size of the the type that ptr points at" and is a very handy thing.
C is a case sensitive language.
ptr=(contactInfo)malloc(2*sizeof(contactInfo));
which should be:
ptr=malloc(2*sizeof(ContactInfo));
Replace
ptr=(contactInfo*)malloc(2*sizeof(contactInfo));
with
ptr=malloc(2*sizeof(struct contactInfo));
struct contactInfo nom,*ptr;
ptr=(contactInfo*)malloc(2*sizeof(contactInfo));
here you are using contactInfo to typcast where as it should be struct contactInfo. and as you have typedef it into ContactInfo you can use that also.
struct contactInfo nom,*ptr;
ptr=(ContactInfo*)malloc(2*sizeof(ContactInfo));