你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

编程喜欢用typedef,为什么?

[复制链接]
gaosmile 发布时间:2020-8-7 20:54
1. typedef 的基本使用
* v5 X3 y* f" a0 s; w8 m0 K/ C
1.1 typedef与结构体的结合使用
typedef 是 C 语言的一个关键字,用来给某个类型起个别名,也就是给C语言中已经存在的一个类型起一个新名字。大家在阅读代码的过程中,会经常见到 typedef 与结构体、联合体、枚举、函数指针声明结合使用。比如下面结构体类型的声明和使用:
  1. 6 a7 y: }. _. M0 a- u4 X0 i- T1 |
  2. struct student
    8 o! T" B- m* U8 N
  3. {
    - i8 z" f1 R6 k$ {% O
  4.   char name[20];7 h* A) _) p+ q3 w$ Y
  5.   int  age;
    0 d: _9 \% M8 w# B, ^2 }! A8 ^
  6.   float score;3 s( N- K+ I" J9 M$ F
  7. };1 z: b* v& T8 Z2 u
  8. struct student stu = {"wit", 20, 99};
复制代码
6 `; T# q5 D1 X; k! ?) ~
在C语言中定义一个结构体变量,我们通常的写法是:
  1. ' \+ z( B1 C5 j3 m( g
  2. struct 结构体名 变量名;
复制代码

( _+ b$ `. q) M! Z0 T( u6 N
前面必须有一个struct关键字打前缀,编译器才会理解你要定义的对象是一个结构体变量。而在C++语言中,则不需要这么做,直接使用:结构体名 变量名就可以了
  1. & V5 @8 L8 S+ N7 U% P8 N
  2. struct student 0 N* J0 p, H. c5 V) F1 |: f' Q
  3. {. u  O5 E( P" Q0 U8 I
  4.   char name[20];$ ~$ D) h* t- M
  5.   int age;9 Q+ V( k0 ?9 r: _2 v
  6.   float score; 1 x) p" v+ R5 Q) Z1 g; |& R
  7. };
    0 A, g- E$ ?& @6 F
  8. int main (void)
    ( T( s$ e* U' k- ^- I
  9. {0 T1 T/ \8 r4 d# h! C) o. S' E" T; L' d+ n
  10.   student stu = {"wit", 20, 99};
    ( b, V2 x6 L. p1 Y$ `
  11.   return 0;, Q7 E$ i2 U9 z( w9 V
  12. }
复制代码
+ K  L6 i+ w* a" Z6 ?
如果我们使用typedef,就可以给student声明一个别名student_t和一个结构体指针类型student_ptr,然后就可以直接使用student_t类型去定义一个结构体变量,不用再写struct,这样会显得代码更加简洁。

  1. 9 O; q1 `2 m& N( B6 ^
  2. #include <stdio.h>+ z7 q3 X" F0 C- t7 \) |
  3. typedef struct student
      k7 Y6 t( t) T& k) ?6 ^6 a  p$ V2 h& [
  4. {
      O8 w! k7 o( T: y
  5.   char name[20];
    ) Z1 B# }, ?2 E/ T" g
  6.   int  age;
    3 ]/ l3 k/ ]! F- d# `5 P6 \- [1 I& ^
  7.   float score;
    $ Z2 D! i1 y* Y4 q2 G3 B0 n7 l
  8. }student_t, *student_ptr;
    2 ?: |6 ~* g& Z" b/ q, P# o
  9. 1 z9 W5 a% n9 L2 P( P; p
  10. int main (void)
    ! @6 |. X/ |! J! e+ g9 v
  11. {
    7 S4 _% k# I  C5 b; X+ L- O( P! c2 M
  12.   student_t   stu = {"wit", 20, 99};
    ( ^3 L8 c6 c  M) c8 s7 J- c
  13.   student_t  *p1 = &stu;2 j2 x3 J# _+ t3 M. R9 Q
  14.   student_ptr p2 = &stu;* r, d0 r' K& K( i
  15.   printf ("name: %s\n", p1->name);
    % Y: |5 c1 s+ ^5 i6 r3 b
  16.   printf ("name: %s\n", p2->name);
    & i" F3 w$ N5 W7 p: {; o9 \! _
  17.   return 0;, q' \* E* [5 I& @- K+ G8 s" E; t
  18. }; F$ U5 V" f8 `6 F! a2 h
  19. 程序运行结果:0 g) Y3 A  X* u# v' M
  20. wit8 Z$ R$ S0 z& \$ `; h
  21. wit* _! l: f' ~- i4 a( u5 t
复制代码
1. 2 typedef 与数组的结合使用
typedef除了与结构体结合使用外,还可以与数组结合使用。定义一个数组,通常我们使用int array[10];即可。我们也可以使用typedef先声明一个数组类型,然后再使用这个类型去定义一个数组。

  1. : g* r8 x' @/ \' A0 }2 f
  2. typedef int array_t[10]; - V& y+ p- ]4 L6 c" |) T, K# h' A
  3. array_t array;' z& o+ `5 Y" ?, u& G  l' }# O
  4. int main (void)2 {) X$ w! k, P) Y8 Y5 D
  5. {
    * j. E, j2 `5 ?7 P% r
  6.   array[9] = 100;( |' O; f0 J! m8 J
  7.   printf ("array[9] = %d\n", array[9]);
    : {: O& G" z# I) w( H% e3 v: B
  8.   return 0;4 L9 c8 X8 s% \- j2 t( `; I* g& n( I
  9. }
复制代码

+ \0 K  P$ C- F- t; l
在上面的demo程序中,我们声明了一个数组类型array_t,然后再使用该类型定义一个数组array,这个array效果其实就相当于:int array[10]。
! D4 p9 E- J; t: K8 _
1.3 typedef 与指针的结合使用2 d$ B# p4 a* s
  1. <font face="Tahoma"><font size="3"><font color="black">
    # l6 o' l$ ~+ [+ c0 Z2 y0 b
  2. typedef char * PCHAR;3 N- f7 T( f; ~# f6 a/ z
  3. int main (void)
    1 I$ k& a( W* y- y$ ^& r# z" g
  4. {
    + X  |8 ^4 G4 W
  5.     //char * str = "学嵌入式,到宅学部落";" D* ]1 B4 [* T& p* A8 P1 M. X
  6.   PCHAR str = "学嵌入式,到宅学部落";
    & V/ z1 N% o# l& n/ M7 P' n
  7.   printf ("str: %s\n", str);
    8 S  v$ r/ C! B
  8.   return 0;
    5 ?8 g  B0 g0 {$ ?# E  m% x
  9. }</font></font></font>
    5 g; U$ y  [7 P; Q1 q
复制代码
* h8 x0 d: @% h
在上面的demo程序中,PCHAR 的类型是 char *,我们使用PCHAR类型去定义一个变量str,其实就是一个char *类型的指针。
1.4 typedef与函数指针的结合使用
定义一个函数指针,我们通常采用下面的形式:
  1. + @& P8 I, Z% z3 g
  2. int (*func)(int a, int b);
复制代码

$ P$ g) B( t2 j& w* v
我们同样可以使用typedef声明一个函数指针类型:func_t

  1. $ J# O3 t! O; Q
  2. typedef int (*func_t)(int a, int b);
    4 @! A. I( \& d, P; W/ o
  3. func_t fp;  // 定义一个函数指针变量
复制代码

& I, Z) B% h0 P% E! X! M: `& j
写个简单的程序测试一下,运行OK:
  1. 7 f: t; O6 k! R8 f# c% ~: U$ ~7 l
  2. typedef int (*func_t)(int a, int b);
    3 A* z' Z! d2 W9 c
  3. int sum (int a, int b)
    - q; n. N& p. ]/ P- @5 H1 X
  4. {4 ]. V4 A  S  C" y
  5.   return a + b;2 C; V% E4 z3 z' P7 l& N$ S
  6. }
    + @' E9 Z& }+ A! T
  7. int main (void)/ Y2 P( f! u( G. `- y
  8. {
    0 U+ n' K, c7 X9 V" z
  9.   func_t fp = sum;
    ( Q- {- h9 H' Y" y& ]+ u
  10.   printf ("%d\n", fp(1,2));/ o: J1 {& y8 W- s. a& z
  11.   return 0;9 q+ C+ o* _6 W6 m2 e( i2 l2 d
  12. }
复制代码

" z3 [. z" X; i( s
为了增加程序的可读性,我们经常在代码中看到下面的声明形式:
  1. + @3 L$ J% f+ u; b6 \% W1 k
  2. typedef int (func_t)(int a, int b);
    4 y" g7 X' m0 T% O& i# b5 c5 ^
  3. func_t *fp = sum;
复制代码

, Z0 Q2 H# F7 H+ g3 n
函数都是有类型的,我们使用typedef给函数类型声明一个新名称:func_t。这样声明的好处是:即使你没有看到func_t的定义,也能够清楚地知道fp是一个函数指针,代码的可读性比上面的好。

- V7 U  L) k3 b6 g- d) X5 A# G9 }
1.5 typedef与枚举的结合使用
  t0 z# o+ P, q, w% K

  1. 1 [' L1 a8 ]8 Z# l, V8 I, O
  2. typedef enum color
    7 B$ X0 a3 p6 f) S5 {
  3. {
    % K; A" {3 ^+ k' O3 f. Y
  4.   red,4 [+ Y, v7 J  ]) p# ]9 R
  5.   white,
    ( b2 ^3 J. L+ r! F. {
  6.   black,' n$ X' Y( R  G+ y
  7.   green,8 r) G( {: e. x6 u" \2 }8 H
  8.   color_num,
    + J7 Y8 F# g! a& g
  9. } color_t;
    1 h- }7 w$ e+ Y( Y7 S8 V) E! Y0 h& U
  10. & G/ x2 b1 |# J; k: b/ E7 H
  11. int main (void)3 O% [- Q8 V+ f' e
  12. {
    * F! z( G& T) B8 Z3 P
  13.   enum color color1 = red;
    % B& g, O6 r; R- ^% \
  14.   color_t    color2 = red;
    0 `0 I+ B. O' g( i: [+ K% I. E# K
  15.   color_t color_number = color_num;$ o" y* F9 L) N4 V. U0 _
  16.   printf ("color1: %d\n", color1);
    + o, ^1 a1 w3 _. p* X4 S
  17.   printf ("color2: %d\n", color2);* \: {& M: L) L1 v7 Y  v3 u: _2 l
  18.   printf ("color num: %d\n", color_number);
    $ r- _9 I+ ?' S. o5 q  {; [
  19.   return 0;
    / E. w2 \. E5 i$ v# }; ~
  20. }
复制代码

( M& a# k7 j* S& c: s

) f9 R/ v2 @- ~) L
枚举与typedef的结合使用方法跟结构体类似:可以使用typedef给枚举类型color声明一个新名称color_t,然后使用这个类型就可以直接定义一个枚举变量。

- Q2 Z8 R3 `) p' [+ Y
2. 使用typedef的优势
不同的项目,有不同的代码风格,也有不同的代码“癖好”。看得代码多了,你会发现:有的代码喜欢用宏,有的代码喜欢使用typedef。那么,使用typedef到底有哪些好处呢?为什么很多人喜欢用它呢?
2.1 可以让代码更加清晰简洁
- p2 Y$ r: K+ ]0 R/ ?7 l- B
  1. 3 x1 A: x) R6 O! `# [! S9 U
  2. typedef struct student# d. n. o* V- n; ^+ m
  3. {
    ( l  `3 t2 z0 P8 ?4 G
  4.   char name[20];' u- r- i2 b; U! M- n/ f% E
  5.   int  age;; r, L) G/ N' S% S+ b! _
  6.   float score;# `  X) K2 @9 ^  n1 E
  7. }student_t, *student_ptr;
    ) f; d+ _# P' d! ~+ |" H6 o
  8. 8 P% p$ O. Y) O8 W' O( S9 S; H/ @
  9. student_t   stu = {"wit", 20, 99};
    / K/ I3 g0 V6 ]5 J/ S8 Z8 V
  10. student_t  *p1 = &stu;
    % v# ]9 z; c. D9 V
  11. student_ptr p2 = &stu;
    " r' }  [- Q" e" V" d
复制代码
0 U- E6 |7 b& A1 h
如示例代码所示,使用typedef,我们可以在定义一个结构体、联合、枚举变量时,省去关键字struct,让代码更加简洁。
2.2 增加代码的可移植性
C语言的int类型,我们知道,在不同的编译器和平台下,所分配的存储字长不一样:可能是2个字节,可能是4个字节,也有可能是8个字节。如果我们在代码中想定义一个固定长度的数据类型,此时使用int,在不同的平台环境下运行可能会出现问题。为了应付各种不同“脾气”的编译器,最好的办法就是使用自定义数据类型,而不是使用C语言的内置类型。
  1. & e7 K. T0 G) e. _$ K- o$ e. b
  2. #ifdef PIC_16
    5 ~) m. l; e0 P# M1 C7 v
  3. typedef  unsigned long U322 w* A3 o, H/ a* j: ?5 l, U9 x
  4. #else
    9 t$ H) U6 {$ q1 g5 {
  5. typedef unsigned int U32  
    3 s/ j* I- v' M, Z
  6. #endif
复制代码

3 p9 {7 d1 y+ Y4 {8 N, a6 p
在16位的 PIC 单片机中,int一般占2个字节,long占4个字节,而在32位的ARM环境下,int和long一般都是占4个字节。如果我们在代码中想使用一个32位的固定长度的无符号类型,可以使用上面方式声明一个U32的数据类型,在代码中你可以放心大胆地使用U32。将代码移植到不同的平台时,直接修改这个声明就可以了。
在Linux内核、驱动、BSP 等跟底层架构平台密切相关的源码中,我们会经常看到这样的数据类型,如size_t、U8、U16、U32。在一些网络协议、网卡驱动等对字节宽度、大小端比较关注的地方,也会经常看到typedef使用得很频繁。
2.3 比宏定义更好用
C语言的预处理指令#define用来定义一个宏,而typedef则用来声明一种类型的别名。typedef跟宏相比,不仅仅是简单的字符串替换,可以使用该类型同时定义多个同类型对象。

  1. . l  j/ u8 R. @; x  |! f
  2. typedef char* PCHAR1;
    * \8 `+ s4 @; N6 z# {1 s
  3. #define PCHAR2 char *2 ?( r) n! ]+ k6 U: {$ u  h
  4. % z0 l9 r2 |( X. p2 [  g: p
  5. int main (void)3 p; w: U, ]* T/ w5 v7 n$ k
  6. {
    " j5 i' D% t# V
  7.   PCHAR1 pch1, pch2;7 m; h' s4 F+ y( ?2 P$ g
  8.   PCHAR2 pch3, pch4;
    0 {( k+ d0 k: p0 H% w  }( }
  9.   printf ("sizeof pch1: %d\n", sizeof(pch1));8 {( t$ b$ V7 k1 v* V3 q
  10.   printf ("sizeof pch2: %d\n", sizeof(pch2));" j) Y1 a7 u8 Z
  11.   printf ("sizeof pch3: %d\n", sizeof(pch3));
    : q+ q; E( K4 |" m8 n. k
  12.   printf ("sizeof pch4: %d\n", sizeof(pch4));
    $ l/ C# _' j7 K, `" o) L
  13.   return 0;
    ! Z  K7 P3 Q+ K$ ]6 X
  14. }
复制代码
% f* b( m) O7 W  x5 y. D
在上面的示例代码中,我们想定义4个指向char类型的指针变量,然而运行结果却是:
  1. : _2 a7 e( W# A8 Q# o% {. X6 |4 j
  2. sizeof pch1: 46 p9 h5 }# m3 p9 \2 V& c/ U2 j
  3. sizeof pch2: 4  @: [- ]( w2 ]% c. c' {
  4. sizeof pch3: 4  n5 _7 G) ^6 k2 A7 Z- T
  5. sizeof pch4: 1
复制代码
* I! ^# a# m" k7 K' @0 B2 c$ M
本来我们想定义4个指向char类型的指针,但是 pch4 经过预处理宏展开后,就变成成了一个字符型变量,而不是一个指针变量。而 PCHAR1 作为一种数据类型,在语法上其实就等价于相同类型的类型说明符关键字,因此可以在一行代码中同时定义多个变量。上面的代码其实就等价于:

  1. + H1 m$ A/ A' U) z- a2 A) Y
  2. char *pch1, *pch2;
    , I9 ^; J% _; b4 O
  3. char *pch3, pch4;0 k/ a6 `- ^  Z" w$ z8 f6 Q) \* J
复制代码
2.4 让复杂的指针声明更加简洁
一些复杂的指针声明,如:函数指针、数组指针、指针数组的声明,往往很复杂,可读性差。比如下面函数指针数组的定义:
  1. ! ^: d8 c2 V4 _9 i* d# w
  2. int *(*array[10])(int *p, int len, char name[]);
复制代码

. c! M& J8 H" h- s* ^/ ~5 Q
上面的指针数组定义,很多人一瞅估计就懵逼了。我们可以使用typedef优化一下:先声明一个函数指针类型func_ptr_t,接着再定义一个数组,就会更加清晰简洁,可读性就增加了不少:
  1. / x, X  S, }: q9 G+ Y, J
  2. typedef int *(*func_ptr_t)(int *p, int len, char name[]);
    7 L" B; Q; l: q: m
  3. func_ptr_t array[10];; \- I5 g7 {( c; v1 Y  ^
复制代码
3. 使用typedef需要注意的地方
通过上面的示例代码,我们可以看到,使用typedef可以让我们的代码更加简洁、可读性更强一些。但是typedef也有很多坑,稍微不注意就可能翻车。下面分享一些使用typedef需要注意的一些细节。
3.1 typedef在语法上等价于关键字
我们使用typedef给已知的类型声明一个别名,其在语法上其实就等价于该类型的类型说明符关键字,而不是像宏一样,仅仅是简单的字符串替换。举一个例子大家就明白了,比如const和类型的混合使用:当const和常见的类型(如:int、char) 一同修饰一个变量时,const和类型的位置可以互换。但是如果类型为指针,则const和指针类型不能互换,否则其修饰的变量类型就发生了变化,如常见的指针常量和常量指针:

  1. . ~8 \. i3 `" w8 F/ Q2 ^
  2. char b = 10;
    ' @; q5 W5 ~1 T) ?1 v, f, U5 ~
  3. char c = 20;
      ~0 O8 _) a: t- V
  4. int main (void)5 x- B* t2 r. O
  5. {  
    # N& Z5 R: E- D8 z% R4 f, E  m; o
  6.   char const *p1 = &b; //常量指针:*p1不可变,p1可变& j  \: x4 a; T) d
  7.   char *const p2 = &b; //指针常量:*p2可变,p2不可变  # p! y+ Z$ h. }  s3 z
  8.   p1  = &c; //编译正常 % F: G1 Q% j8 K
  9.   *p1 = 20; //error: assignment of read-only location  4 ^6 |& s$ M, F1 y4 j
  10.   p2  = &c; //error: assignment of read-only variable`p2'& G$ i1 f# w9 D# [8 g
  11.   *p2 = 20; //编译正常% L' I* n  P2 m0 W* T, D
  12.   return 0;) `8 q* n: |3 a$ B8 V
  13. }
复制代码
6 b/ t) n$ p% T$ M2 X
当typedef 和 const一起去修饰一个指针类型时,与宏定义的指针类型进行比较:

  1. % H5 ?6 e* b& H
  2. typedef char* PCHAR2;
    . S9 A/ c- I8 k2 s  g  ^
  3. #define PCHAR1 char * 1 A, u, P1 t. o" b4 Y8 n
  4. char b = 10;) s; q. c* H& g* s8 k- n
  5. char c = 20;8 s4 ?, Q4 X* K0 E5 a: g
  6. int main (void)
    - v; @/ ~5 {6 e. h$ P0 ~
  7. {  
    % ?/ t8 H; N8 K' S9 h7 C
  8.   const PCHAR1 p1 = &b;" A8 @! R2 Y% X: c1 ~
  9.   const PCHAR2 p2 = &b;
    5 B7 V6 w0 R& {/ y4 |, t, c3 x
  10.   p1  = &c; //编译正常
    7 c4 O# J1 y8 v
  11.   *p1 = 20; //error: assignment of read-only location  
    : l7 v. j+ ]. U* j- u) _
  12.   p2  = &c; //error: assignment of read-only variable`p2'
    $ k: {5 `  g# T# v  l7 F' b1 q8 m
  13.   *p2 = 20; //编译正常
    , f' l3 l" N& i. G
  14.   return 0;
    8 }" R$ |  l( ], O+ f4 k3 c; i
  15. }
复制代码

) x) q8 w0 \0 \' W, V
运行程序,你会发现跟上面的示例代码遇到相同的编译错误,原因在于宏展开仅仅是简单的字符串替换:

  1.   p, R* i& P# R( R
  2. const PCHAR1 p1 = &b; //宏展开后是一个常量指针
      r) l! b4 O0 F6 u% J- z& I
  3. const char * p1 = &b; //其中const与类型char的位置可以互换
复制代码

3 r$ v* \2 h& V) _+ I) `
而在使用PCHAR2定义的变量p2中,PCHAR2作为一个类型,位置可与const互换,const修饰的是指针变量p2的值,p2的值不能改变,是一个指针常量,但是*p2的值可以改变。
  1. 7 y. n  |8 O1 H: n6 o7 f
  2. const PCHAR2 p2 = &b; //PCHAR2此时作为一个类型,与const可互换位置$ T; ~* K6 s% _- n( {; y) `
  3. PCHAR2 const p2 = &b; //该语句等价于上条语句
    # r1 Z! H# `9 _* I
  4. char * const p2 = &b; //const和PCHAR2一同修饰变量p2,const修饰的是p2!
复制代码

' x# a, r9 `; O, A
3.2 typedef是一个存储类关键字
没想到吧,typedef在语法上是一个存储类关键字!跟常见的存储类关键字(如:auto、register、static、extern)一样,在修饰一个变量时,不能同时使用一个以上的存储类关键字,否则编译会报错:

  1. 7 Z# D: }* W; F  [2 K: X5 e
  2. typedef static char * PCHAR;
    / @. S( y) J* |/ e( x4 k
  3. //error: multiple storage classes in declaration of `PCHAR'* U  w0 R3 z4 q& U! T5 ~
复制代码
3.3 typedef 的作用域
跟宏的全局性相比,typedef作为一个存储类关键字,是有作用域的。使用typedef声明的类型跟普通变量一样遵循作用域规则:包括代码块作用域、文件作用域等。
  1. + B7 Y9 D2 f4 i+ g; |$ }% S* w
  2. typedef char CHAR;% f$ M$ b. z% z) [

  3. 8 B$ f: w7 j; b8 v4 Q8 k
  4. void func (void)6 v8 Z  `' u0 ~! c  o: u
  5. {
    9 m+ C- N9 V2 ], a! g- ], T% `
  6.   #define PI 3.14" r0 z0 E  O& F% }; p: l: m2 W5 {
  7.   typedef short CHAR;
    * x% k( h/ Y( Y. \2 T! k
  8.   printf("sizeof CHAR in func: %d\n",sizeof(CHAR)); : O6 ?6 D8 V+ p8 ^0 m# L
  9. }
    6 {; O; V+ D, o5 L5 Y' e
  10. 2 g& ], f) r. C& C) F3 b  U
  11. int main (void)
    & M" ]* T8 ^' \/ I& P
  12. {  " l$ a1 p$ f9 s1 K8 L' Y
  13.   printf("sizeof CHAR in main: %d\n",sizeof(CHAR));! `9 y' M' R. h/ v
  14.   func();) v1 \' I( R  n
  15.   typedef int CHAR;1 Y, q2 f& @: G& Y6 \$ l- W: f. \6 Z% P
  16.   printf("sizeof CHAR in main: %d\n",sizeof(CHAR));
    1 Z' F0 X- @. R8 S9 n
  17.   printf("PI:%f\n", PI);  
    ' V6 w0 s3 p5 S1 l! C; W
  18.   return 0;# \2 Q* L/ X. b9 s( ?1 N# L
  19. }
复制代码

. [3 I7 \7 V0 Z5 X
宏定义在预处理阶段就已经替换完毕,是全局性的,只要保证引用它的地方在定义之后就可以了。而使用typedef声明的类型则跟普通变量一样遵循作用域规则。上面代码的运行结果为:
  1. ; H4 m! V: c$ |
  2. sizeof CHAR in main: 18 B$ ]) ]) x0 X" W' b
  3. sizeof CHAR in func: 2
    * k& X5 r7 M0 R; h! d$ f
  4. sizeof CHAR in main: 47 H2 z: L( _2 H# T. t1 K
  5. PI:3.140000
    & W% v, R! v$ U2 E# D" Y
复制代码

8 m. y- B# r; S
4 如何避免typedef的滥用?
通过上面的学习我们可以看到:使用typedef可以让我们的代码更加简洁、可读性更好。在实际的编程中,越来越多的人也开始尝试使用typedef,甚至到了“过犹不及”的滥用地步:但凡遇到结构体、联合、枚举都要用个typedef封装一下,不用就显得你low、你菜、你的代码没水平。
其实typedef也有副作用,不一定非得处处都用它。比如上面我们封装的STUDENT类型,当你定义一个变量时:
  1. 1 L4 m) {/ R  l2 A9 A
  2. STUDENT stu;
    2 z  L2 x! J, s7 M
复制代码
不看STUDENT的声明,你知道stu的含义吗?未必吧。而如果我们直接使用struct定义一个变量,则会更加清晰,让你一下子就知道stu是个结构体类型的变量:

  1. 2 \# T# z7 i) X
  2. struct  student stu;( D: C- P( u' i2 M) `
复制代码
一般来讲,当遇到以下情形时,使用typedef可能会有用,否则可能会适得其反:
  • 创建一个新的数据类型
  • 跨平台、指定长度的类型:如U32/U16/U8
  • 跟操作系统、BSP、网络字宽相关的数据类型:如size_t、pid_t等
  • 不透明的数据类型:需要隐藏结构体细节,只能通过函数接口访问的数据类型

    ; O2 z' ]: j7 S8 p& H# `* |
在阅读Linux内核源码过程中,你会发现大量使用了typedef,哪怕是简单的int、long都使用了typedef。这是因为:Linux内核源码发展到今天,已经支持了太多的平台和CPU架构,为了保证数据的跨平台性和可移植性,所以很多时候不得已使用了typedef,对一些数据指定固定长度:如U8/U16/U32等。但是内核也不是到处到滥用,什么时候该用,什么不该用,也是有一定的规则要遵循的,具体大家可以看kernel Document中的 CodingStyle 中关于typedef的使用建议。
. A# F* k& O* Z
赞 收藏 1 评论0 发布时间:2020-8-7 20:54

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版