Understand the typedef in C language

(Translated text, the content has been deleted and changed)

1. Definition and scope of typedef

    Typedef allows us to create aliases for existing types or user-defined types, in the format:

typedef <existing_names_of_datatype> <alias__userGiven_name>;

    Example:

typedef int myint;

    myint is an alias for int. From then on, we can use myint instead of int to define new int variables:

myint i = 0; // this statement is equivalent to int i = 0;

    We can even create multiple aliases for the same type. E.g:

typedef int myint, integer;

    This statement creates two aliases for the int type, namely myint and integer.
    We can write typedef declarations wherever declarations are allowed. However, it should be noted that the scope of the declaration depends on the location of the typedef statement. If the definition is placed outside all functions, then the scope is global, and any function can use aliases instead of the original name. On the other hand, if the definition is declared in a function, then the scope is local, and only this function can use aliases.
    Example 1: Use typedef to declare local aliases

#include<stdio.h>
void foo(void);

int main()
{
    
    
    typedef unsigned char uchar;
    uchar ch = 'a';
    printf("ch inside main() : %c\n", ch);
    foo();
    return 0;
}

void foo(void)
{
    
    
    // uchar ch = 'a'; // Error
    unsigned char ch = 'z';
    printf("ch inside foo() : %c\n", ch);
}

    Output:

ch inside main() : a
ch inside foo(): z

    The typedef is defined in the main() function, so we can only use the alias uchar in main(). Try to uncomment line 15 and compile the program, you will get an error from the compiler because the alias uchar is not available in the foo() function.
    Example 2: Use typedef to declare global alias

#include<stdio.h>

typedef unsigned char uchar;
void foo(void);

int main()
{
    
    
    uchar ch = 'a';
    printf("ch inside main() : %c\n", ch);
    foo();
    return 0;
}

void foo(void)
{
    
    
    uchar ch = 'z';
    printf("ch inside foo() : %c\n", ch);
}

    Output:

ch inside main() : a
ch inside foo(): z

    Here typedef declaration is higher than all functions, so any function can use the alias uchar to declare variables of type unsigned char.

2. Define aliases for pointers
typedef int * iptr;

    After this statement, iptr is an alias for a pointer to int or (int*).
    Example:

iptr a, *b; // same as int *a, **b;
iptr arr[10]; // same as int *arr[10];

    In the first declaration, a is a pointer to int and b is a pointer to int. In the second declaration, arr is an array of 10 integer pointers.
    Example:

#include        <stdio.h>
typedef int * iptr;

int main()
{
    
    
        iptr    arr[10];
        int a;
        arr[1] = &a;

        a = 56;
        printf("%d\n", a);
        printf("%d\n", *(arr[1]));

        return 0;
}

    Here, arr is an array, each element holds a pointer, and the output result:

56
56
3. Define aliases for the array
typedef int iarr[10];

    iarr is an alias for an array consisting of 10 integer elements.

iarr a, b, c[5]; // same as int a[10], b[10], c[10][5];

    In this declaration, a and b are arrays of 10 integers, and c is a two-dimensional array of 10*5.
    Example:

#include<stdio.h>
typedef int iarr[10];

int main()
{
    
    
    int i;

    // same as int a[10] = {12,43,45,65,67,87,89,91,14,19}
    iarr a = {
    
    12,43,45,65,67,87,89,91,14,19}; 

    for(i = 0; i < 10; i++)
    {
    
    
        printf("a[%d] = %d\n",i ,a[i]);
    }
    return 0;
}

    Output:

a[0] = 12
a[1] = 43
a[2] = 45
a[3] = 65
a[4] = 67
a[5] = 87
a[6] = 89
a[7] = 91
a[8] = 14
a[9] = 19
4. Define aliases for the structure
struct book
{
    
    
    char title[20];
    char publisher[20];
    char author[20];
    int year;
    int pages;
};

typedef struct book Book;

    After this statement, Book is an alias for struct book. So there is no need to use struct book to declare new structure variables, we can use Book directly.

Book b1 = {
    
    "The Alchemist", "TDM Publication" , "Paulo Coelho", 1978, 331 };

    We can also combine the definition of the structure with the typedef declaration. The syntax is as follows:

typedef struct tagname 
{
    
    
    data_type member1;
    data_type member1;
    ...
} newname;

    Let us rewrite the definition of the structure book with the new syntax of typedef:

typedef struct book
{
    
    
    char title[20];
    char publisher[20];
    char author[20];
    int year;
    int pages;
} Book;

    The following program demonstrates how to use typedef in a structure:

#include<stdio.h>

typedef struct book
{
    
    
    char title[20];
    char publisher[20];
    char author[20];
    int year;
   int pages;
} Book;

int main()
{
    
    

    Book b1 = {
    
    
                "The Zahir",
                "Harper Perennial" ,
                "Paulo Coelho",
                 2005,
                 336
              };

    printf("Title: %s\n", b1.title);
    printf("Author: %s\n", b1.author);

    return 0;
}

    Output:

Title: The Zahir
Author: Paulo Coelho

    Similarly, we can use typedef with union.

5. typedef vs #define

    It must be pointed out that typedef is not a preprocessor directive, so its interpretation is handled by the compiler, not by the preprocessor. Recall that the #define directive allows us to define extensions for any text, on the other hand typedef is used to create aliases for any data type.
    However, in some cases, #define and typedef will produce the same result. Examples are as follows:

#define directive typedef declaration
#define uchar unsigned char typedef unsigned char uchar;
Test statement uchar ch; uchar ch;
Converted result unsigned char ch; unsigned char ch;

    The following are situations where #define and typedef produce different results:

#define directive typedef declaration
#define fp float * typedef float * fp;
Test statement fp a, b, c; fp a, b, c;
Converted result float *a, b, c; float *a, *b, *c;

    In the second case, when the preprocessor sees the statement

fp a, b, c;

    It replaces fp with float *. So the above statement becomes:

float *a, b, c;

    On the other hand, typedef has more semantic meaning, so the compiler will not replace it like a preprocessor.
    The following program demonstrates the difference between #define and typedef:

#include<stdio.h>
#define ptr int * // replace occurence of ptr by int *
typedef int * iptr; // iptr is an alias of pointer to int or int*

int main()
{
    
    
    ptr a, b, c; // same as int *a, b, c;
    iptr p1, p2, p3; // same as int *p1, *p2, *p3

    b = 10;
    c = 20;

    a = &b;
    p1 = &b;

    p2 = &c;
    p3 = &c;

    printf("Value at a = %d\n", *a); // print value of b
    printf("Value at p2 = %d\n", *p2); // print value of b

    return 0;
}

    Output:

Value at a = 10
Value at p2 = 20
6. Advantages of typedef

    It makes the program more readable. Of course, Book b1 is more readable and intuitive than struct book b1.
    It makes the program portable. Let me explain, look at the prototype of the sizeof() operator and malloc() function.

size_t sizeof(type);

void *malloc(size_t size);

    As you know, both prototypes use the size_t type, and we have told you to treat size_t as unsigned int, but this is not entirely correct. The C standard stipulates that sizeof() must return an integer, but the system decides which type to return. This is because the C Standards Committee feels that not offering options may be the best choice for each platform. Therefore, they created new types, such as size_t, time_t, etc., and let the system use typedef to set these names to a specific type. Therefore, the type of size_t of one system can be unsigned int, and the type of size_t of another system can be unsigned long int.

Reference documents

[1]OverIQ.com.typedef statement in C[EB/OL].https://overiq.com/c-programming-101/typedef-statement-in-c/,2020年7月27日.

Guess you like

Origin blog.csdn.net/zsx0728/article/details/115282698