一 . typedef:
1.什么是typedef
typedef 是C语言中的一个关键字,它的作用是给一个已经存在的类型起一个别名。
typedef 可以为基本数据类型、自定义数据类型(结构体、共用体、枚举类型)、数组和指针定义简洁的类型名称。一旦用户在程序中定义了自己的数据类型名称,就可以在该程序中用自己的数据类型名称来定义变量的类型、数组的类型、指针变量的类型与函数的类型等。
typedef 在编译时处理,有类型检查功能,不同于 #define 的简单文本替换。
typedef 可以增强程序的可读性和可移植性。
2.typedef 用法
1).基本数据类型的重定义:
示例:
#include<stdio.h>
typedef int i;
typedef char ch;
typedef long long int li;
int main()
{
i a = 5;
li b = 10;
ch c = 'a';
printf("%d\n", a);
printf("%lld\n", b);
printf("%c\n", c);
return 0;
}
运行结果如下图所示:
在这里,我们将 int、char、long long int 分别重定义为i、ch、li,并通过新的类型名声明变量 a,b,c 由此我们可以知道,当使用 typedef 定义类型名后,我们可以使用新的类型名声明与原类型名声明的变量相同的变量。
注:使用 typedef 定义类型名后,原类型名作用不变。
2).自定义数据类型重定义:
a.结构体:
示例:
#include<stdio.h>
struct student
{
char name[20];
int age;
char sex[7];
};
typedef struct student stu;
int main()
{
stu a = { "wang", 10,"male" };
printf("%d", a.age);
return 0;
}
运行结果如下图所示:
在这里我们对结构体 struct student 重定义为stu ,并通过 stu 声明变量 a 并进行初始化。
我们也可以在结构体定义时进行重定义,如下:
#include<stdio.h>
typedef struct student
{
char name[20];
int age;
char sex[7];
}stu;
int main()
{
stu a = { "wang", 10,"male" };
printf("%d", a.age);
return 0;
}
此时,结构体变量 第一个名称可以省略,如下:
#include<stdio.h>
typedef struct
{
char name[20];
int age;
char sex[7];
}stu;
int main()
{
stu a = { "wang", 10,"male" };
printf("%d", a.age);
return 0;
}
b.共用体:
共用体的重定义与结构体相似
示例:
#include<stdio.h>
union un
{
char a;
int b;
};
typedef union un u;
int main()
{
u b = {0};
b.a = 'a';
printf("%d", b.b);
return 0;
}
运行结果如下图:
在这里我们对共用体 union un 重定义为 u ,并通过 u 声明变量共用体变量 b 并进行初始化。
我们也可以像结构体一样在定义共用体时进行重定义,如下:
#include<stdio.h>
typedef union un
{
char a;
int b;
}u;
int main()
{
u b = { 0 };
b.a = 'a';
printf("%d", b.b);
return 0;
}
c.枚举变量:
示例:
#include<stdio.h>
enum week
{
one = 1,
two,
three,
four,
five,
six,
seven
};
typedef enum week w;
int main()
{
w a = one;
printf("%d", a);
return 0;
}
在这里我们定义枚举类型 week 后对 week 进行重定义为 w ,并通过 w 声明枚举变量 a 并进行初始化。
运行结果如下图:
同时,也可以像共用体和结构体一样,在定义枚举类型时进行重定义,如下:
#include<stdio.h>
typedef enum week
{
one = 1,
two,
three,
four,
five,
six,
seven
}w;
int main()
{
w a = one;
printf("%d", a);
return 0;
}
3).数组的重定义:
示例:
#include<stdio.h>
typedef int (i)[5];
int main()
{
i a = { 1,2,3,4,5 };
printf("%d", *(a+2));
return 0;
}
结果如下图所示:
在这里我们将包含五个整型的数组重定义为i ,并通过 i 声明枚举变量 a 并进行初始化。
4).函数的重定义:
示例:
#include<stdio.h>
int fun(void)
{
return 20;
}
typedef int(f)(void) ;
int main()
{
f* a = fun;
printf("%d", (a()));
return 0;
}
结果如下图所示:
这里我们定义一个返回整型,并且无参数的函数类型为 f ,通过 f 声明一个函数变量并赋值为fun。
5).指针的重定义:
a.指针:
示例:
#include<stdio.h>
typedef int* i;
int main()
{
int a = 0;
i b = &a;
printf("%d", *b);
return 0;
}
运行结果如下图:
这里我们将 int* 类型重定义为 i,并通过 i 声明整型指针变量 b ,并将整型变量 a 的地址赋给 b。
b.数组指针重定义:
示例:
#include<stdio.h>
typedef int(*i)[5];
int main()
{
int a[5] = { 1,2,5,6,9 };
i b = &a;
printf("%d", *((*b)+3));
return 0;
}
运行结果如下图:
这里我们将指向包含五个整型的数组的指针重定义为 i ,通过 i 声明 数组指针变量 b,并赋值为数组a的地址。
c.指针数组的重定义:
指针数组,顾名思义就是包含多个指针的数组。
#include<stdio.h>
typedef int* i[5];
int main()
{
int a = 10, b = 20, c = 30;
i arr = { &a,&b,&c };
printf("%d\n", **arr);
printf("%d\n", **(arr+1));
printf("%d\n", **(arr+2));
return 0;
}
运行结果如下图所示:
这里我们对指针数组重定义为 i ,通过 i 声明变量 arr ,并初始化为 &a, &b, &c。
d.函数指针:
示例:
#include<stdio.h>
int fun(void)
{
return 20;
}
typedef int( *f)(void) ;
int main()
{
f a = fun;
printf("%d", (a()));
return 0;
}
返回值如下图:
这里将返回值为 int (整型),并且没有参数的函数类型重定义为 (*f),(即 f 为指向函数的指针类型),并将函数 fun 赋给函数变量 a 。
3.注意事项:
1).小心typedef的陷阱:
我们先看一个简单的代码:
#include<stdio.h>
typedef int* i;
int main()
{
int a = 10;
const i b = &a;
return 0;
}
对于这个代码,我们会下意识的认为 const 的用法 “左定值,有定向”,所以这个代码相当于 “const int * b;”,实则不然,typedef 不同于宏,不是简单的字符替换,这个代码相当于 "int * const b;" 。
2).对于多个储存类关键字:
在语法上,typedef 不没有储存类功能,但在语法上属于储存类关键字,因此,下图这种情况是错误的:
typedef static int a;
在这里,typedef 占据了储存类关键字的位置,不再允许其他储存类关键字的出现。