What is the use of typedef? - c

What is the use of typedef keyword in C ?
When is it needed?

typedef is for defining something as a type. For instance:
typedef struct {
int a;
int b;
} THINGY;
...defines THINGY as the given struct. That way, you can use it like this:
THINGY t;
...rather than:
struct _THINGY_STRUCT {
int a;
int b;
};
struct _THINGY_STRUCT t;
...which is a bit more verbose. typedefs can make some things dramatically clearer, specially pointers to functions.

From wikipedia:
typedef is a keyword in the C and C++ programming languages. The purpose of typedef is to assign alternative names to existing types, most often those whose standard declaration is cumbersome, potentially confusing, or likely to vary from one implementation to another.
And:
K&R states that there are two reasons for using a typedef. First, it provides a means to make a program more portable. Instead of having to change a type everywhere it appears throughout the program's source files, only a single typedef statement needs to be changed. Second, a typedef can make a complex declaration easier to understand.
And an argument against:
He (Greg K.H.) argues that this practice not only unnecessarily obfuscates code, it can also cause programmers to accidentally misuse large structures thinking them to be simple types.

Typedef is used to create aliases to existing types. It's a bit of a misnomer: typedef does not define new types as the new types are interchangeable with the underlying type. Typedefs are often used for clarity and portability in interface definitions when the underlying type is subject to change or is not of importance.
For example:
// Possibly useful in POSIX:
typedef int filedescriptor_t;
// Define a struct foo and then give it a typedef...
struct foo { int i; };
typedef struct foo foo_t;
// ...or just define everything in one go.
typedef struct bar { int i; } bar_t;
// Typedef is very, very useful with function pointers:
typedef int (*CompareFunction)(char const *, char const *);
CompareFunction c = strcmp;
Typedef can also be used to give names to unnamed types. In such cases, the typedef will be the only name for said type:
typedef struct { int i; } data_t;
typedef enum { YES, NO, FILE_NOT_FOUND } return_code_t;
Naming conventions differ. Usually it's recommended to use a trailing_underscore_and_t or CamelCase.

Explaining the use of typedef in the following example. Further, Typedef is used to make the code more readable.
#include <stdio.h>
#include <math.h>
/*
To define a new type name with typedef, follow these steps:
1. Write the statement as if a variable of the desired type were being declared.
2. Where the name of the declared variable would normally appear, substitute the new type name.
3. In front of everything, place the keyword typedef.
*/
// typedef a primitive data type
typedef double distance;
// typedef struct
typedef struct{
int x;
int y;
} point;
//typedef an array
typedef point points[100];
points ps = {0}; // ps is an array of 100 point
// typedef a function
typedef distance (*distanceFun_p)(point,point) ; // TYPE_DEF distanceFun_p TO BE int (*distanceFun_p)(point,point)
// prototype a function
distance findDistance(point, point);
int main(int argc, char const *argv[])
{
// delcare a function pointer
distanceFun_p func_p;
// initialize the function pointer with a function address
func_p = findDistance;
// initialize two point variables
point p1 = {0,0} , p2 = {1,1};
// call the function through the pointer
distance d = func_p(p1,p2);
printf("the distance is %f\n", d );
return 0;
}
distance findDistance(point p1, point p2)
{
distance xdiff = p1.x - p2.x;
distance ydiff = p1.y - p2.y;
return sqrt( (xdiff * xdiff) + (ydiff * ydiff) );
} In front of everything, place the keyword typedef.
*/

typedef doesnot introduce a new type but it just provide a new name for a type.
TYPEDEF CAN BE USED FOR:
Types that combine arrays,structs,pointers or functions.
To facilitate the portability , typedef the type you require .Then when you port the code to different platforms,select the right type by making changes only in the typedef.
A typedef can provide a simple name for a complicated type cast.
typedef can also be used to give names to unnamed types. In such cases, the typedef will be the only name for said type.
NOTE:-SHOULDNT USE TYPEDEF WITH STRUCTS. ALWAYS USE A TAG IN A STRUCTURE DEFINITION EVEN IF ITS NOT NEEDED.

from Wikipedia:
"K&R states that there are two reasons for using a typedef. First ... . Second, a typedef can make a complex declaration easier to understand."
Here is an example of the second reason for using typedef, simplifying complex types (the complex type is taken from K&R "The C programming language second edition p. 136).
char (*(*x())[])()
x is a function returning pointer to array[] of pointer to function returning char.
We can make the above declaration understandable using typedefs. Please see the example below.
typedef char (*pfType)(); // pf is the type of pointer to function returning
// char
typedef pfType pArrType[2]; // pArr is the type of array of pointers to
// functions returning char
char charf()
{ return('b');
}
pArrType pArr={charf,charf};
pfType *FinalF() // f is a function returning pointer to array of
// pointer to function returning char
{
return(pArr);
}

It can alias another type.
typedef unsigned int uint; /* uint is now an alias for "unsigned int" */

typedef unsigned char BYTE;
After this type definition, the identifier BYTE can be used as an abbreviation for the type unsigned char, for example..
BYTE b1, b2;

Related

OOP and forward declaration of structure in C

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)
{
...
}

C access enum from struct

My problem is that car_name_str could not be resolved. Why is it not callable and I want to keep the code structure?
I want to keep the structure as struct with union and enum (different datatypes).
Template: How can mixed data types (int, float, char, etc) be stored in an array?
//car_union.h
typedef struct {
enum { number_of_seats_int, car_cost_float, car_name_str } type;
union {
int number_of_seats;
float car_cost;
char* car_name;
} value;
}Car_data_ex[30][3];
extern Car_data_ex *Car_data[30][3];
//fill_car.c
#include "car_union.h"
Car_data_ex *Car_data[30][3];
Car_data[0][0]->type = car_name_str; //-> because pointer but doesnt work
Car_data[0][0]->value->car_name= "land rover";
Car_data[0][1]->type = car_cost_float; //doesnt work
Car_data[0][1]->value->car_cost= 45000;
Just remove the [30][3] from the type def, like this
#include <stdio.h>
//car_union.h
typedef struct {
enum { number_of_seats_int, car_cost_float, car_name_str } type;
union {
int number_of_seats;
float car_cost;
char* car_name;
} value;
}Car_data_ex;
extern Car_data_ex *Car_data[30][3];
int main() {
Car_data_ex *Car_data[30][3];
Car_data[0][0]->type = car_name_str; //-> because pointer but doesnt work
Car_data[0][0]->value.car_name= "land rover";
Car_data[0][1]->type = car_cost_float; //doesnt work
Car_data[0][1]->value.car_cost= 45000;
}
Regardless of what's in your struct, when you do
typedef struct Car_dataStructTag{
//...
}Car_data_ex[30][3];
(I've tagged the struct so it can be referred to by struct Car_dataStructTag),
then Car_data_ex is a type alias resolving to struct Car_dataStructTag [30][3]
which means
extern Car_data_ex *Car_data[30][3];
is fully equivalent to
extern struct Car_dataStructTag (*Car_data[30][3])[30][3];
which means Car_data[x][y] is a pointer to a two-dimensional array of struct Car_dataStructTag,
which is definitely not something you can apply -> to.
Try:
typedef struct Car_dataStructTag{
//...
}Car_data_ex[30][3];
extern Car_data_ex *Car_data[30][3];
extern struct Car_dataStructTag (*Car_data[30][3])[30][3];
in a compiler -- it gets accepted, confirming the declaration equivalence.
Running into situations such as this one is why it's generally considered ill-advisable to typedef arrays or pointers.
You have over complexified everything.
A typedef is just to give an alias to a (complex) type. Here the type is a struct containing an enum and an union. So it should be:
typedef struct {
enum { number_of_seats_int, car_cost_float, car_name_str } type;
union {
int number_of_seats;
float car_cost;
char* car_name;
} value;
}Car_data_ex;
Next, using an array of pointers can make sense, but provided each pointer in the array does point to a true object. Here you only want a plain (2D) array:
Car_data_ex Car_data[30][3];
Once this has been done, you can write with no error or warning:
Car_data[0][0].type = car_name_str;
Car_data[0][0].value.car_name= "land rover";
Car_data[0][1].type = car_cost_float;
Car_data[0][1].value.car_cost= 45000;
And you should avoid extern Car_data_ex Car_data[30][3];. It declares a global array, that will have to be defined in one single compilation unit (.c file). Here again, it can make sense, but IMHO it is a rather advanced feature that can be hard to correctly use. And nothing in the shown code lets think that is is required...

What does passing two aliases to `typedef struct` mean?

What does *B in the following code mean? I understand this mixture between typedef and struct. However, this *B is strange.
typedef struct Something
{
...
}
A, *B;
I saw multiple questions asking about mixing typedef with struct but non of them talked about this double definition.
This is a less-common use case for the typedef keyword that allows you to define two or more type aliases in a single line. Here, this says
make an alias named A that represents the struct itself, and
make an alias named B that represents a pointer to the struct.
In that sense, it's similar to writing something like
int A, *B;
Here, this declares an integer named A and a pointer to an integer named B. The syntax here involving the * works very similarly to what's going on in the typedef statement, except that instead of introducing variables it's introducing types.
Another way to see this: this is equivalent to breaking things apart into two separate statements:
typedef struct {
...
} A;
typedef A* B;
Here, the first one says "A now refers to this struct type, and B now refers to a pointer to an A."
I have seen this type of definition a lot in Microsoft code:
typedef struct {
int count;
char buffer[128];
} BUFFER, *PBUFFER;
It allows code like this to be written:
void read_buffer(PBUFFER pBuffer) {
// Do something with pBuffer
}
int main(void) {
BUFFER buffer;
read_buffer(&buffer);
return 0;
}
To directly answer your question: This kind of typedef allows a type and a pointer to a type to be defined at the same location in the code.

storage size of ‘s’ isn’t known + pointer to pointer

Greeting,
I faced the error of "Assignment_1.c:10:18: error: storage size of ‘s’ isn’t known" I am not expert in using pointer to pointer, I want to have a dynamic sized array of dynamic sized words. Any idea?
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
int size = MAX;
typedef struct{
int numberOfWords,averageWordLength,id;
char ** words;
}sentence;
void main(){
struct sentence s;
s.numberOfWords=3;
s.averageWordLength=5;
s.id=1;
s->words= malloc(size * sizeof(s));
//printf("%s",s.words);
}
Do not use typedef for structs unless you are trying to create an opaque type. This is wrong. struct is a great hint to C developers. Linus had a good description of this:
It's a mistake to use typedef for structures and pointers. When you
see a
vps_t a;
in the source, what does it mean?
In contrast, if it says
struct virtual_container *a;
you can actually tell what "a" is.
Lots of people think that typedefs "help readability". Not so. They
are useful only for:
(a) totally opaque objects (where the typedef is actively used to
hide
what the object is).
Example: "pte_t" etc. opaque objects that you can only access using
the proper accessor functions.
NOTE! Opaqueness and "accessor functions" are not good in themselves.
The reason we have them for things like pte_t etc. is that there
really is absolutely _zero_ portably accessible information there.
(b) Clear integer types, where the abstraction helps avoid
confusion
whether it is "int" or "long".
u8/u16/u32 are perfectly fine typedefs, although they fit into
category (d) better than here.
NOTE! Again - there needs to be a _reason_ for this. If something is
"unsigned long", then there's no reason to do
typedef unsigned long myflags_t;
but if there is a clear reason for why it under certain circumstances
might be an "unsigned int" and under other configurations might be
"unsigned long", then by all means go ahead and use a typedef.
(c) when you use sparse to literally create a new type for
type-checking.
...
Do not declare a bunch of variables in a row. You only confuse others by doing that.
And of course you cannot refer to a member field using . operator, you have to use ->. That being said, you code should look something like:
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
struct sentence {
int numberOfWords;
int averageWordLength;
int id;
char **words;
};
int main()
{
struct sentence s;
s.numberOfWords = 3;
s.averageWordLength = 5;
s.id = 1;
s.words = malloc(MAX * sizeof(s));
/* printf("%s",s.words); */
return EXIT_SUCCESS;
}
Also consider having `words as the first member of the structure or you waste memory due to misalignment on platforms where alignment of a pointer is greater than integer.
Use '->' when the structure's object is a pointer type. This should work:
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
int size = MAX;
typedef struct{
int numberOfWords,averageWordLength,id;
char *words;
}sentence;
void main(){
sentence s;
s.numberOfWords=3;
s.averageWordLength=5;
s.id=1;
s.words= malloc(size * sizeof(s));
//printf("%s",s.words);
}
In
typedef struct {
int numberOfWords, averageWordLength, id;
char **words;
} sentence;
you create a unnamed struct and an alias for that struct. The alias name is sentence.
You now have a new type in your code. The new type name is sentence. If you provided a tag there would be 2 new type names: sentence and struct tag.
typedef struct tag {
whatever;
} sentence;
Also note the typedef isn't really needed
struct tag {
whatever;
};
The snippet above defines a new type named struct tag.

Why often a struct's tagName differs from the typedef's name?

Sometimes I see code like this (I hope I remember it correctly):
typedef struct st {
int a; char b;
} *stp;
While the usual pattern that I familiar with, is:
typedef struct st {
int a; char b;
} st;
So what's the advantage in the first code example?
You probably mean this:
typedef struct ST {
/* fields omitted */
} *STP;
The asterisk is at the end of the statement. This simply means "define the type STP to be a pointer to a struct of this type". The struct tag (ST) is not needed, it's only useful if you want to be able to refer to the struct type by itself, later on.
You could also have both, like so:
typedef struct {
/* fields omitted */
} ST, *STP;
This would make it possible to use ST to refer to the struct type itself, and STP for pointers to ST.
Personally I find it a very bad practice to include the asterisk in typedefs, since it tries to encode something (the fact that the type is a pointer) into the name of the type, when C already provides its own mechanism (the asterisk) to show this. It makes it very confusing and breaks the symmetry of the asterisk, which appears both in declaration and use of pointers.
It's a habit that stems from the time when typedef names and struct tagnames were in the same namespace. See http://blogs.msdn.com/oldnewthing/archive/2008/03/26/8336829.aspx
I think you are talking about :
typedef struct{
int a;
char b;
} object, *objectPointer;
This means that (new) type objectPointer is a pointer to struct (object) defined above. Its easy to declare pointers to object struct this way. For instance,
objectPointer A = (objectPointer)malloc(sizeof(object));
A->a = 2;
Now, A is a pointer to struct object and you can access its variables as described above.
In case, objectPointer was not defined,
struct object *A = (struct object *)malloc(sizeof(object));
A->a = 2;
So, I guess objectPointer is more intuitive and easy to use.
I hope that the first code would say a compiler error ,
I see no good reason for the typedef name be different from the tag name.
Now, the reason for which the tag name needs to be typedefed if you don't want to use
struct tag v;
but
tag v;
is probably an historical one. For as long as I remember, C had typedef but I don't know if it was true when struct have been introduced (handling of typedef is a nuisance in the C grammar). In the old code I've seen, using typedef for struct isn't done, and there are things like unix
struct stat;
int stat(const char*, struct stat*);
which would break with an automatic typedef. One those are introduced, changing is quite difficult (yes, C++ has automatic typedef but C++ has special wording to handle that case of overloading and it would be yet another complication).

Resources