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

编程喜欢用typedef,为什么?

[复制链接]
gaosmile 发布时间:2020-8-7 20:54
1. typedef 的基本使用' K8 c8 X  V2 {4 j  @( q
1.1 typedef与结构体的结合使用
typedef 是 C 语言的一个关键字,用来给某个类型起个别名,也就是给C语言中已经存在的一个类型起一个新名字。大家在阅读代码的过程中,会经常见到 typedef 与结构体、联合体、枚举、函数指针声明结合使用。比如下面结构体类型的声明和使用:
  1. % C  N6 q% l( Y& Z8 T4 k# g, g! w
  2. struct student
    4 q* g7 t3 B3 f% o1 s
  3. {
    * q4 I2 d. T7 K6 V" T: U, _
  4.   char name[20];" {5 H1 U) C( f( J
  5.   int  age;$ X% y( L1 G5 u1 {( Y  T/ W+ U
  6.   float score;
    : B* e& A' ?* M' s
  7. };
    1 H7 k9 c/ k( b* E" \$ V
  8. struct student stu = {"wit", 20, 99};
复制代码

# }  R1 R$ J# r' S* K6 j
在C语言中定义一个结构体变量,我们通常的写法是:
  1. 3 G: h' G$ S, ~- L, j+ K3 [8 {
  2. struct 结构体名 变量名;
复制代码

- P* h* ^( ~1 Q' j, p
前面必须有一个struct关键字打前缀,编译器才会理解你要定义的对象是一个结构体变量。而在C++语言中,则不需要这么做,直接使用:结构体名 变量名就可以了

  1. 0 m, \, Z( s0 i2 i) p! m  q: r
  2. struct student 3 c* @! [# ]3 H1 Q% d
  3. {3 `3 Z# l% l( P) i
  4.   char name[20];
    $ b8 z* b3 m* `
  5.   int age;* r# |1 K( V8 C2 U
  6.   float score;
    ( |/ a- {  k0 L+ j
  7. };( X) ?4 ^, S4 S1 K
  8. int main (void)9 }$ |' A. i. M- r0 h
  9. {
    , D9 e& O" g4 d/ V& b2 \+ g9 m
  10.   student stu = {"wit", 20, 99};) x# t7 }1 `) g
  11.   return 0;( _5 |- @8 d$ o1 t/ R+ j$ R
  12. }
复制代码

* Q9 _$ @0 @& Y7 E
如果我们使用typedef,就可以给student声明一个别名student_t和一个结构体指针类型student_ptr,然后就可以直接使用student_t类型去定义一个结构体变量,不用再写struct,这样会显得代码更加简洁。

  1. ! D! M- ^. _; R
  2. #include <stdio.h>
    - l3 r  D' E1 N# ?% ?  V; `! F
  3. typedef struct student" j$ g, j9 J, o" W" g% C
  4. {" `7 I. x) c8 O
  5.   char name[20];8 y- g$ l4 ~* n
  6.   int  age;
    " |0 X0 b1 V9 o! E1 ], l; R3 v/ k
  7.   float score;  I% Z- N/ v6 P, l
  8. }student_t, *student_ptr;
    - Z, s" t$ Y3 k  {) t: w1 W% _- H4 d

  9. 6 R8 b5 q2 C) f. B, P
  10. int main (void)& L* l9 U- Q& o7 n9 L5 I
  11. {
    # U+ g: I9 L) n
  12.   student_t   stu = {"wit", 20, 99};
    ( @8 x! Y7 m. s* s" w
  13.   student_t  *p1 = &stu;
    0 x9 R3 y4 U+ b4 Y2 L  H4 i2 e
  14.   student_ptr p2 = &stu;
    + r4 R: B9 [& ~. w' `
  15.   printf ("name: %s\n", p1->name);& X  Q" I9 ]  n' R$ j5 n/ ~
  16.   printf ("name: %s\n", p2->name);
    ) e. g( a, N3 g& S
  17.   return 0;
    " |$ j& @+ U8 m2 t& D
  18. }4 }* j4 r- D, L; P9 _7 A
  19. 程序运行结果:
    + Y, y) ?1 a4 K. H6 U0 E: l/ t
  20. wit
    7 S* z) \0 X3 V7 N
  21. wit6 v- K; F2 e" D' j: E. U5 `3 d8 H1 e+ i
复制代码
1. 2 typedef 与数组的结合使用
typedef除了与结构体结合使用外,还可以与数组结合使用。定义一个数组,通常我们使用int array[10];即可。我们也可以使用typedef先声明一个数组类型,然后再使用这个类型去定义一个数组。
  1. : X3 N5 B2 p) ?
  2. typedef int array_t[10]; 3 u* r! O- }3 c9 Y$ l6 X- M! V+ G
  3. array_t array;
    + o, H& o2 U0 ?; k6 T- S
  4. int main (void)& g: K* u: O1 z: M# d* a% t& H
  5. {; y# \& g7 {* X" H7 w+ Z3 [
  6.   array[9] = 100;: l  `) o: a* K7 N8 ~' }! l
  7.   printf ("array[9] = %d\n", array[9]);
    3 e* N! V3 I) o
  8.   return 0;+ }4 W1 p8 {! Y- W/ k
  9. }
复制代码
6 s' c) u# V& T: d9 x
在上面的demo程序中,我们声明了一个数组类型array_t,然后再使用该类型定义一个数组array,这个array效果其实就相当于:int array[10]。
/ s! f- A+ F8 l/ p  o8 L7 d5 q" T
1.3 typedef 与指针的结合使用
' M. Q; F7 B6 C" K- u+ g
  1. <font face="Tahoma"><font size="3"><font color="black">
    & G3 f- P) n( e" }/ D
  2. typedef char * PCHAR;
    4 w; ?5 D7 J: U9 m+ g7 X( O, X
  3. int main (void)1 y- e% i8 X  k" w9 S4 q* C3 p, E- p
  4. {2 n* j5 d7 x( d+ o( E& z. B
  5.     //char * str = "学嵌入式,到宅学部落";( h+ ~/ x- X( ]& E8 t/ c, [0 _* P
  6.   PCHAR str = "学嵌入式,到宅学部落";
    # {; X4 y7 y$ p  E5 f" F3 U6 ]% S
  7.   printf ("str: %s\n", str);( q& ?# g$ X, \0 c, `3 ~* G
  8.   return 0;
    - Y+ A4 K+ ^# [$ O  i- @! _3 z5 B9 D
  9. }</font></font></font>
    % E* q' w# p0 P2 L/ }
复制代码

! U# e$ V1 c; l4 W! i0 S  ?
在上面的demo程序中,PCHAR 的类型是 char *,我们使用PCHAR类型去定义一个变量str,其实就是一个char *类型的指针。
1.4 typedef与函数指针的结合使用
定义一个函数指针,我们通常采用下面的形式:
  1. ) L+ P: G7 T: y0 e, I/ k
  2. int (*func)(int a, int b);
复制代码

" I$ ]( I$ k; d6 m! \$ x
我们同样可以使用typedef声明一个函数指针类型:func_t
  1. * T2 N: ^; }5 a- z
  2. typedef int (*func_t)(int a, int b);" D4 v: r/ h6 b3 C* z
  3. func_t fp;  // 定义一个函数指针变量
复制代码
$ [. z) t9 L7 I7 ?5 W4 g. [
写个简单的程序测试一下,运行OK:

  1. / ?; V) Q0 Y3 j4 K# g6 E: ?( I3 }
  2. typedef int (*func_t)(int a, int b);
    5 H* S$ a8 M- ?/ C
  3. int sum (int a, int b)
    / t; a; r/ S6 D; u& J
  4. {- T% C3 X) r$ j! x! F0 |+ I  K
  5.   return a + b;$ j  D$ g& u/ Z! B9 P9 X4 s5 r
  6. }
    $ ?3 [) g- s5 k  g4 N/ V
  7. int main (void)
    0 Z* w4 q/ d- t. q
  8. {
    3 j/ l. P$ g+ B
  9.   func_t fp = sum;0 W9 i9 n% H+ p3 Q* a! g# i- p
  10.   printf ("%d\n", fp(1,2));# \3 s% u( }- k% a2 t* ?- h
  11.   return 0;6 `  X7 k7 H% W( s, @# S
  12. }
复制代码

, ?8 B  J4 J1 q7 R  G
为了增加程序的可读性,我们经常在代码中看到下面的声明形式:
  1. 5 t+ V8 \6 R. k! a
  2. typedef int (func_t)(int a, int b);
    / I, S( Y9 G+ ~6 n0 }* w
  3. func_t *fp = sum;
复制代码
5 z- {1 R/ Y0 c! L4 y
函数都是有类型的,我们使用typedef给函数类型声明一个新名称:func_t。这样声明的好处是:即使你没有看到func_t的定义,也能够清楚地知道fp是一个函数指针,代码的可读性比上面的好。
- x/ E/ N  d2 y& V/ _
1.5 typedef与枚举的结合使用$ ~2 W% T+ U; \; c% ]+ Z2 _

  1. 6 L/ s3 K' o) `
  2. typedef enum color
    - S' l( z+ K  ^5 O7 h6 P. P
  3. {
    ( D9 f' n* j% A6 ~/ [/ D
  4.   red,
    # s9 c6 h, S3 k
  5.   white,8 U4 T5 i: Q' y( n$ C! Y: V
  6.   black,
    . F" C/ E; N' N4 \
  7.   green,
    / }+ A$ j! H% t9 \
  8.   color_num,
    ' E- F' j  J, `
  9. } color_t;' W$ ^0 U3 i6 ]/ @  ?4 ]

  10. 0 _/ N; a9 l, ?) s, L
  11. int main (void)' Z6 k% Y# n1 }" ?4 Z! B
  12. {
    / y! u2 S4 i9 B4 S$ h8 P2 o# d
  13.   enum color color1 = red;
    2 e7 I" C- B- @3 m6 {
  14.   color_t    color2 = red;
    1 b7 T, J6 {7 h+ O( |! _; W$ D, D
  15.   color_t color_number = color_num;0 V3 P" S5 D! C) B# w2 `( d
  16.   printf ("color1: %d\n", color1);
    * L% l0 l( {2 G+ R! a& c" O  H: ~
  17.   printf ("color2: %d\n", color2);! X& @, A6 a& f- h. w6 U# L- ?4 L
  18.   printf ("color num: %d\n", color_number);! g8 S; r* t& R
  19.   return 0;
    1 a% o- {# l) C
  20. }
复制代码
! h2 C2 z+ @% w. v
! u/ k4 `7 |# a' \! ~. F
枚举与typedef的结合使用方法跟结构体类似:可以使用typedef给枚举类型color声明一个新名称color_t,然后使用这个类型就可以直接定义一个枚举变量。

) }& k# A: K$ _9 }! `
2. 使用typedef的优势
不同的项目,有不同的代码风格,也有不同的代码“癖好”。看得代码多了,你会发现:有的代码喜欢用宏,有的代码喜欢使用typedef。那么,使用typedef到底有哪些好处呢?为什么很多人喜欢用它呢?
2.1 可以让代码更加清晰简洁, X" |* `6 s2 N1 T- G

  1. 4 a+ w: }- ^6 `* j
  2. typedef struct student( y: S& g+ `! A" c1 [. S0 [! R
  3. {
    ' G2 ?+ B1 e8 U0 W% m# z' ~
  4.   char name[20];/ ^3 w3 k) c. M1 p' [
  5.   int  age;$ n3 \5 H: j  `# o
  6.   float score;
    9 q) Q/ k! A* M: R! a
  7. }student_t, *student_ptr;
    6 i( F  O  I* a% k$ Q
  8. 7 }8 R5 l* o/ H' x8 o0 b9 L! H3 X
  9. student_t   stu = {"wit", 20, 99};5 \$ Q( j% O* l' I, B0 b" K
  10. student_t  *p1 = &stu;
    . l$ o& F! x) n9 A  Z, n4 F2 ]+ v
  11. student_ptr p2 = &stu;
    ! F. U& w, O2 K' d" ~0 d: R
复制代码

' z* ?. }1 ?/ d. O/ P4 }
如示例代码所示,使用typedef,我们可以在定义一个结构体、联合、枚举变量时,省去关键字struct,让代码更加简洁。
2.2 增加代码的可移植性
C语言的int类型,我们知道,在不同的编译器和平台下,所分配的存储字长不一样:可能是2个字节,可能是4个字节,也有可能是8个字节。如果我们在代码中想定义一个固定长度的数据类型,此时使用int,在不同的平台环境下运行可能会出现问题。为了应付各种不同“脾气”的编译器,最好的办法就是使用自定义数据类型,而不是使用C语言的内置类型。

  1. 6 l/ \9 Y" h9 ~# h/ [' K5 ^
  2. #ifdef PIC_16
    4 m' y1 p% y8 ?6 a
  3. typedef  unsigned long U322 Z2 B3 F" y/ t( X' @$ H. u
  4. #else$ m# {9 s7 _& M2 b. ]
  5. typedef unsigned int U32  
    . y& w- @/ O* f% O
  6. #endif
复制代码

; Z+ a; K3 g* ?% S8 H" U- d
在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. - H3 X; K" C) a
  2. typedef char* PCHAR1;' r! e8 x8 P! D* k/ I. c
  3. #define PCHAR2 char *
    0 A" {2 b6 u+ \8 B& L, A+ z7 S
  4. 6 A1 i; g$ @& m  ?! V( x7 O
  5. int main (void)! h, e) o' f$ s) q
  6. {! K+ |# j% |5 A- X, @1 }0 l
  7.   PCHAR1 pch1, pch2;1 Q! y3 y1 w/ h
  8.   PCHAR2 pch3, pch4;- U$ u5 H# P$ a( t  h5 p" k; a
  9.   printf ("sizeof pch1: %d\n", sizeof(pch1));# n0 Y( C+ U2 Q9 y. ^' p9 Z
  10.   printf ("sizeof pch2: %d\n", sizeof(pch2));
    / m+ L. x4 C/ r
  11.   printf ("sizeof pch3: %d\n", sizeof(pch3));# m% R+ g4 `4 c  X) ^% @% s
  12.   printf ("sizeof pch4: %d\n", sizeof(pch4));
    # r' F0 Y9 O0 V! V) {) Q  M  r
  13.   return 0;# y( S$ w2 D# p2 s. e0 \2 q1 @
  14. }
复制代码

2 q9 \9 r3 Q8 b1 d
在上面的示例代码中,我们想定义4个指向char类型的指针变量,然而运行结果却是:

  1. 1 w8 V2 b7 f/ t9 @  f- O9 G
  2. sizeof pch1: 43 _6 W- ~3 I8 x- w5 L
  3. sizeof pch2: 4
    3 G8 ]3 C& m" L1 t+ |
  4. sizeof pch3: 4
    % p9 W: J7 v2 k! n, D
  5. sizeof pch4: 1
复制代码

6 z, N, D" a% n+ `7 i  j
本来我们想定义4个指向char类型的指针,但是 pch4 经过预处理宏展开后,就变成成了一个字符型变量,而不是一个指针变量。而 PCHAR1 作为一种数据类型,在语法上其实就等价于相同类型的类型说明符关键字,因此可以在一行代码中同时定义多个变量。上面的代码其实就等价于:
  1. 4 c6 O3 Z5 ^2 T5 Z) `* ^
  2. char *pch1, *pch2;
    % @  y0 {; _1 N: v
  3. char *pch3, pch4;, _# G7 ^' W* |
复制代码
2.4 让复杂的指针声明更加简洁
一些复杂的指针声明,如:函数指针、数组指针、指针数组的声明,往往很复杂,可读性差。比如下面函数指针数组的定义:
  1. * j1 s# R, ~2 S7 @
  2. int *(*array[10])(int *p, int len, char name[]);
复制代码

2 k& \& y+ s  M
上面的指针数组定义,很多人一瞅估计就懵逼了。我们可以使用typedef优化一下:先声明一个函数指针类型func_ptr_t,接着再定义一个数组,就会更加清晰简洁,可读性就增加了不少:

  1. ' N- d5 Q+ `" O- e0 f
  2. typedef int *(*func_ptr_t)(int *p, int len, char name[]);
    5 `) b2 j' A% ^9 a. u; D
  3. func_ptr_t array[10];: S* A) |. u9 d6 T' ~7 N
复制代码
3. 使用typedef需要注意的地方
通过上面的示例代码,我们可以看到,使用typedef可以让我们的代码更加简洁、可读性更强一些。但是typedef也有很多坑,稍微不注意就可能翻车。下面分享一些使用typedef需要注意的一些细节。
3.1 typedef在语法上等价于关键字
我们使用typedef给已知的类型声明一个别名,其在语法上其实就等价于该类型的类型说明符关键字,而不是像宏一样,仅仅是简单的字符串替换。举一个例子大家就明白了,比如const和类型的混合使用:当const和常见的类型(如:int、char) 一同修饰一个变量时,const和类型的位置可以互换。但是如果类型为指针,则const和指针类型不能互换,否则其修饰的变量类型就发生了变化,如常见的指针常量和常量指针:
  1. 0 Q6 K- Q& o  i7 S4 Q
  2. char b = 10;
    ' V! u4 s7 k( ~$ d/ B; ]
  3. char c = 20;
    * E1 Z: D0 r) p: B2 _
  4. int main (void)
    . o( _9 I( _" k- }
  5. {  / Y2 o9 W4 Y% o1 o- ]
  6.   char const *p1 = &b; //常量指针:*p1不可变,p1可变
    6 @( ^) |- g2 Y
  7.   char *const p2 = &b; //指针常量:*p2可变,p2不可变  7 f6 K/ d$ p6 j) E6 p1 {
  8.   p1  = &c; //编译正常
    6 A5 z% g1 N+ }" A/ b$ h3 F
  9.   *p1 = 20; //error: assignment of read-only location  / I! D" w- k) @+ \$ p6 s5 E2 V4 U
  10.   p2  = &c; //error: assignment of read-only variable`p2'
    ' f/ P% ]- B" I2 m3 K% I1 m# B
  11.   *p2 = 20; //编译正常- ]0 H& T6 y  c% {( B
  12.   return 0;
    ! N. `- `5 M) V& N4 Y
  13. }
复制代码
3 ^5 |1 C- W" L
当typedef 和 const一起去修饰一个指针类型时,与宏定义的指针类型进行比较:
  1. , ?: H1 J/ @: u2 X5 @% \4 G, G
  2. typedef char* PCHAR2;9 f7 U- G! Z4 W6 b. C5 [
  3. #define PCHAR1 char * / G/ I9 ^% B  Z) I
  4. char b = 10;3 \0 C7 I+ N$ _# |! X
  5. char c = 20;: e1 l. ]5 N" A* C8 u) _
  6. int main (void)
    $ D2 E* G$ a6 {9 @
  7. {  1 S6 b4 _- h+ \8 M- J- }/ b
  8.   const PCHAR1 p1 = &b;+ S9 _6 @& o5 {% U
  9.   const PCHAR2 p2 = &b;
    $ y5 M6 j2 x; d5 e% @$ Z
  10.   p1  = &c; //编译正常
    ; x7 V1 I+ f6 w1 q1 A* x/ a
  11.   *p1 = 20; //error: assignment of read-only location  $ t/ Z* f7 |& r5 K
  12.   p2  = &c; //error: assignment of read-only variable`p2'
    6 `" m, A# p& b/ f& R/ E
  13.   *p2 = 20; //编译正常
    6 ~. Z+ h. L% Q$ [- Q
  14.   return 0;
    ( h3 I3 d! m$ z0 j7 r' v) U  H
  15. }
复制代码
3 r1 V9 r5 k+ g: `9 D: A2 r9 h$ t
运行程序,你会发现跟上面的示例代码遇到相同的编译错误,原因在于宏展开仅仅是简单的字符串替换:

  1. : _5 n, T' R! e3 e% D
  2. const PCHAR1 p1 = &b; //宏展开后是一个常量指针1 z9 m' M2 ^; l" X4 a
  3. const char * p1 = &b; //其中const与类型char的位置可以互换
复制代码
1 s9 c' ~1 a6 t2 s/ m6 l8 J
而在使用PCHAR2定义的变量p2中,PCHAR2作为一个类型,位置可与const互换,const修饰的是指针变量p2的值,p2的值不能改变,是一个指针常量,但是*p2的值可以改变。
  1. : _$ H  k: g# r9 ^7 Y8 f/ @6 z- p; p
  2. const PCHAR2 p2 = &b; //PCHAR2此时作为一个类型,与const可互换位置9 a7 n5 T7 e7 g, Q, Y) h- L# [
  3. PCHAR2 const p2 = &b; //该语句等价于上条语句
    " |; O- G2 d1 H( P
  4. char * const p2 = &b; //const和PCHAR2一同修饰变量p2,const修饰的是p2!
复制代码
1 {) u' C% f. f$ o, {8 M3 D. M- s
3.2 typedef是一个存储类关键字
没想到吧,typedef在语法上是一个存储类关键字!跟常见的存储类关键字(如:auto、register、static、extern)一样,在修饰一个变量时,不能同时使用一个以上的存储类关键字,否则编译会报错:

  1. $ f6 w1 f8 P/ S! d9 `
  2. typedef static char * PCHAR;( {9 x  l' ^4 T
  3. //error: multiple storage classes in declaration of `PCHAR'
    4 t( r; v7 Y) [0 p+ Z% m- y$ F
复制代码
3.3 typedef 的作用域
跟宏的全局性相比,typedef作为一个存储类关键字,是有作用域的。使用typedef声明的类型跟普通变量一样遵循作用域规则:包括代码块作用域、文件作用域等。
  1. + v0 m  v7 O& b2 H7 @
  2. typedef char CHAR;
    1 G6 T$ y/ p3 W9 K0 F  o
  3. 9 M( }. a# M9 N# Z- ^
  4. void func (void), m. m/ A! t* O3 m
  5. {7 q/ p' Y0 K6 U! h  @6 O  `
  6.   #define PI 3.14
    , A5 X! k) E! S% r) i
  7.   typedef short CHAR;+ p% n! }) q. E' g: R
  8.   printf("sizeof CHAR in func: %d\n",sizeof(CHAR));
    1 W2 T# K; a: ]; f
  9. }
    . p3 p$ J5 N! T! X; R
  10. ) d* P- I0 v) a% q3 {
  11. int main (void)
    " y8 a1 E; A0 ?5 P5 z0 {9 A- v! u
  12. {  ' S4 N6 `" ^! p" J8 n( A
  13.   printf("sizeof CHAR in main: %d\n",sizeof(CHAR));
    ! H$ m% {5 H+ g$ s% W
  14.   func();
    + d+ c2 B/ ?  M, N4 A/ C) {5 ^
  15.   typedef int CHAR;4 f+ N# @, W9 W# B
  16.   printf("sizeof CHAR in main: %d\n",sizeof(CHAR));" ~4 U5 f7 ?  U: n) a+ w
  17.   printf("PI:%f\n", PI);  * a, F. o; _' i6 E( \
  18.   return 0;- l! f. v: L9 E) I4 ~- W/ \, q
  19. }
复制代码

* B' j' f5 R# `" W8 e1 C
宏定义在预处理阶段就已经替换完毕,是全局性的,只要保证引用它的地方在定义之后就可以了。而使用typedef声明的类型则跟普通变量一样遵循作用域规则。上面代码的运行结果为:

  1. 3 b- {% p" n% F) N9 z3 S
  2. sizeof CHAR in main: 1
    0 E4 M2 W7 ^$ e8 h4 {* ~8 d. R
  3. sizeof CHAR in func: 2+ p% Y5 z+ {9 Y0 E
  4. sizeof CHAR in main: 4. r. t2 M' m6 z4 h/ ~, ^" F7 K
  5. PI:3.140000% u- f' J( d' p( _2 _
复制代码
* K4 e  w- F+ _. v  G
4 如何避免typedef的滥用?
通过上面的学习我们可以看到:使用typedef可以让我们的代码更加简洁、可读性更好。在实际的编程中,越来越多的人也开始尝试使用typedef,甚至到了“过犹不及”的滥用地步:但凡遇到结构体、联合、枚举都要用个typedef封装一下,不用就显得你low、你菜、你的代码没水平。
其实typedef也有副作用,不一定非得处处都用它。比如上面我们封装的STUDENT类型,当你定义一个变量时:

  1. 0 q* b, {+ g  i: b( }9 ^, B
  2. STUDENT stu;( }8 L+ A: y! g
复制代码
不看STUDENT的声明,你知道stu的含义吗?未必吧。而如果我们直接使用struct定义一个变量,则会更加清晰,让你一下子就知道stu是个结构体类型的变量:

  1. : Z; }( O6 n; O. E' k& @
  2. struct  student stu;/ H$ B/ u9 R8 X
复制代码
一般来讲,当遇到以下情形时,使用typedef可能会有用,否则可能会适得其反:
  • 创建一个新的数据类型
  • 跨平台、指定长度的类型:如U32/U16/U8
  • 跟操作系统、BSP、网络字宽相关的数据类型:如size_t、pid_t等
  • 不透明的数据类型:需要隐藏结构体细节,只能通过函数接口访问的数据类型

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

举报

0个回答

所属标签

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