munotes®

typedef

Chapter Thirteen

Syllabus topic 1, "Introduction: Algorithms, History of C, Structure of C Program. Program Characteristics, Compiler, Linker and preprocessor, pseudo code statements and flowchart symbols, Desirable program characteristics. Program structure. Compilation and Execution of a Program, C Character Set, identifiers and keywords, data types and sizes, constants and its types, variables, Character and character strings, typedef, typecasting"

Pages 60 to 63 of 222

In one line

typedef gives an existing type a second name, so that a declaration can say what a value means rather than only how it is stored.

Why you would want to

unsigned long says how a value is stored. It says nothing about what it is. Compare:

unsigned long a;
unsigned long b;

with

typedef unsigned long Bytes;
typedef unsigned long Milliseconds;

Bytes a;
Milliseconds b;

The machine code is identical. What changed is that a reader of the second version knows what the two variables hold, and a reader of the first has to find out.

There is a second reason, and in practice it is the one that makes typedef indispensable: some C type names are genuinely hard to read. The declaration of a pointer to a function returning int and taking two double parameters is int (*f)(double, double), and a typedef turns that into a name you can use like any other.

The syntax, and the trick for remembering it

typedef existing-type new-name;

The trick: write the declaration you would have written, then put typedef in front of it, and the name being declared becomes the name of the type.

unsigned long bytes;            /* declares a VARIABLE called bytes      */
typedef unsigned long bytes;    /* declares a TYPE called bytes          */

That rule is worth more than memorising cases, because it handles the awkward ones automatically:

char line[80];                  /* a variable: an array of 80 char       */
typedef char Line[80];          /* a type: "array of 80 char"            */
Line a, b;                      /* two arrays of 80 char each            */
int *p;                         /* a variable: pointer to int            */
typedef int *IntPtr;            /* a type: "pointer to int"              */
IntPtr p, q;                    /* BOTH are pointers, which is the point */

That last line is the one case where typedef does something #define cannot. With #define IntPtr int , the line IntPtr p, q; expands to int p, q;, which declares one pointer and one plain int. The typedef declares two pointers, because it names a type rather than substituting text.

A working example

#include <stdio.h>

typedef unsigned int Marks;
typedef double Percentage;
typedef char Name[20];

Percentage as_percentage(Marks got, Marks total)
{
    return (Percentage) got * 100.0 / total;
}

int main(void)
{
    Name student = "Anita";
    Marks got = 63;
    Marks total = 75;
    Percentage pc = as_percentage(got, total);

    printf("%s scored %u out of %u, which is %.2f per cent\n",
           student, got, total, pc);
    printf("sizeof(Marks) is %zu and sizeof(unsigned int) is %zu\n",
           sizeof(Marks), sizeof(unsigned int));
    return 0;
}
Anita scored 63 out of 75, which is 84.00 per cent
sizeof(Marks) is 4 and sizeof(unsigned int) is 4

The function signature now reads as what it does: it takes marks and returns a percentage. sizeof(Marks) and sizeof(unsigned int) are the same number, which is the proof that nothing new was created.

munotes.in60

typedef

What typedef does NOT do, with proof

It does not create a new type. The name is an alias, and the two are the same type for every purpose the language has.

#include <stdio.h>

typedef int Metres;
typedef int Feet;

int main(void)
{
    Metres distance = 100;
    Feet height = 6;

    /* Nonsense, and the compiler has no objection: both are int. */
    int nonsense = distance + height;

    printf("adding metres to feet gives %d, and -Wall -Wextra said nothing\n",
           nonsense);
    return 0;
}
adding metres to feet gives 106, and -Wall -Wextra said nothing

That program compiles clean. Adding metres to feet is meaningless and the compiler cannot know it, because Metres and Feet are both spellings of int. So typedef is documentation, not protection. If you need the compiler to keep two quantities apart, you need two different structure types, which is chapter 42.

It does not allocate anything. typedef is a declaration, not a definition of an object. No memory is set aside.

It cannot extend a type. typedef cannot make an integer bigger or add an operation. It only renames.

It is not a macro. The pointer example above is the proof. typedef is handled by the compiler and understands the grammar of declarations; #define is handled by the preprocessor and understands only text.

typedef#define
Handled byCompilerPreprocessor
Knows it is a typeYesNo
Obeys scopeYesNo
X p, q; where X is a pointer typeBoth are pointersFirst a pointer, second is not
Can rename an array or function typeYesNot usefully
Can define a constant or a code fragmentNoYes

Where typedef really earns its place

Three uses account for nearly all of it in real C.

1. Shortening a structure name. In C, a structure's name includes the keyword: struct student. A typedef lets you write Student. This is the commonest use by a wide margin, and chapter 42 gives it.

2. Naming a pointer-to-function type, which is otherwise unreadable.

typedef int (*Comparison)(const void *, const void *);

3. Making a program's own vocabulary portable. The standard library does this everywhere, and you have already used the results: size_t is a typedef for whatever unsigned type is right for a size on this machine, and FILE, time_t, ptrdiff_t and wchar_t are all typedef names. That is why sizeof prints with %zu and not %u: the actual type behind size_t differs between machines, and the typedef is what lets your program not care.

munotes.in61

typedef

That last point is the honest answer to "why does typedef exist": it lets a program name a type by its purpose while the compiler chooses the representation.

Naming style

There is no rule, and there are two common conventions.

  • Capitalised: Marks, Percentage, Student. Used in this book, because it makes a type name visible at a glance.
  • _t suffix: marks_t, student_t. Common in systems code, and it imitates the library's size_t and time_t.

Strictly, names ending in _t are reserved by POSIX for the system's own headers, so the capitalised form is the safer habit. Either way, be consistent within a program.

Quick revision

  • typedef existing-type new-name; gives a type a second name.
  • The trick: write the variable declaration, put typedef in front, and the name declared becomes a type name.
  • It creates no new type: sizeof proves it, and two typedef names for int add together without complaint.
  • It allocates nothing and is handled by the compiler, not the preprocessor.
  • Unlike #define, it knows it is declaring a type, so IntPtr p, q; makes two pointers.
  • It obeys scope, so a typedef inside a function is local to it.
  • Main uses: shortening struct names, naming function-pointer types, and giving a portable name to a machine-dependent type. size_t, FILE and time_t are library typedefs.

Test yourself

1. Write a typedef that names the type "array of 10 double", and declare two such arrays with it.

typedef double Vector[10];
Vector a, b;

2. Is sizeof(Marks) the same as sizeof(unsigned int) after typedef unsigned int Marks;?

Yes. Marks is another name for unsigned int, not a new type.

3. What is wrong with #define IntPtr int * followed by IntPtr p, q;?

It expands to int * p, q;, so p is a pointer and q is a plain int. A typedef would have made both pointers.

4. Will the compiler stop you adding a Metres to a Feet if both are typedef int?

No. They are the same type, so there is nothing for it to object to. Use two distinct structure types if you want that checked.

5. Name three typedef names from the standard library and say why each is a typedef rather than a fixed type.

size_t, time_t and FILE. Each hides a representation that differs between implementations, so a program can name the purpose and let the library choose the type.

6. Can a typedef be written inside a function?

Yes, and it then obeys the same scope rules as any other declaration in that block: it is visible from that point to the end of the block and nowhere else.

munotes.in62

typedef

What can be asked on this, and how to answer it

"What is typedef? Explain with an example." Define it as a way of giving an existing type an additional name, give the syntax, give two examples of which one is an array or pointer type, and say plainly that no new type is created. The last part is where the marks separate.

"Distinguish between typedef and #define." Give the table's rows: compiler against preprocessor, type-aware against text substitution, scoped against not scoped, and the pointer example where the two genuinely differ.

"What are the advantages of typedef?" Readability, because a declaration can name the purpose of a value; brevity, because struct student becomes Student; portability, because a program can use a name whose underlying type the implementation chooses; and maintainability, because a representation can be changed in one line.

"Does typedef create a new data type?" No. It creates a new name for an existing type. The two names are interchangeable everywhere, and the compiler will not distinguish values of them.

munotes.in63

The rest of this subject

These notes are cut from the University's printed syllabus. Open the syllabus itself for the same subject.

Report or request
Done!