|
又有一段时间没写文章了,今天给大家分享的是c语言中typedef的各种用法;在这之前,想必大部分人和我一样,对于typedef的用法,用的最多用法就是给一个数据类型起一个别名(也就是方便我们写代码),例如下面就是我们常见的写法:$ W7 \8 A! O' L( u( Z 第一种:是在许多实时操作系统中经常会看到的写法: 1typedef unsigned char UINT8;. ^8 ^# W2 ^$ L& j* j$ _2 3typedef unsigned short UINT16;# z* o' m& R' N/ I5 ` 4typedef unsigned int UINT32;; t( F7 v$ I! h- s0 w3 U9 S 59 w% \5 U3 b' y8 Y 6typedef signed char INT8;' h, g: R+ O3 J3 y- B2 X( G 7typedef signed short INT16;9 m7 Z5 p+ g) b; U3 F 8 9typedef signed int INT32;: X$ M9 T' L( G2 s g+ Y6 Z% _ 10 11typedef float FLOAT; 12 13typedef double DOUBLE; 14 15typedef char CHAR;5 r f ?; \, E+ i% a' U , `. O0 e3 X+ K1 L. _3 V* P( ]% M 第二种:就是我们在stm32里面结构体定义的时候经常会看到(标准库操作):% \, a/ j$ L+ A+ W" k
今天我们要讲的typedef用法,平时大家一般可能都没怎么注意到,这里给大家总结一下,以便下次特别是在读linux内核代码的时候(或者其它地方的代码),不要懵逼了,看不懂(到时候和我一样到处查博客,当然自己亲手获取的知识才是真正为自己所有)。这里你对这个用法稍微有一个印象就行,不要死记硬背,理解为主!9 G3 L4 U& E8 P# K7 p# { 一、typedef和const结合的陷阱: 这个用法还是比较少见的,而且万一哪天你找工作,在笔试的时候遇到这个,那真是有点尴尬的(如果你不会的话,只能靠瞎猜了)。我们先来看一段代码(你可以先不看我下面代码讲解,自己先看一下会不会丢入这个常规思维里面去理解):2 E/ C6 K- u5 H+ D + o3 Y& v# D7 \; _ 1#include <stdio.h>$ ?5 B$ t9 x& C$ H* N, b0 \0 U3 | 2 3typedef int *PINT; 4 5 int main(void) 6 { 7 int a=23;& D! f* k/ J5 ~7 [ 8& F; [" \8 }2 C9 K 9 const PINT b=&a; & |6 ?5 U Y% i& H/ r; G' b 10 *b=8;: h! Y$ E, R. I( s" R 11 //////////////////////////////////// 12 const int * c=&a;5 Z9 B, @2 s; G 13 *c=43;; v9 v8 p# ]$ q$ W 14 15 16 printf("the *b is %d\n",*b);: p+ _; u0 S8 _. j# l2 u# N, @ 17; A0 k$ A, t2 ?1 b" } 18 return 0; d" O( `; c4 q2 t8 f/ o 19 }3 O/ J' j% u: e 运行结果:6 B: b' I2 Q: R: |
这里你会看到,有一个报错,这个错误很好理解,不足为怪,但是上面的typedef定义的int *类型的指针,取了一个别名叫PINT,然后再main函数里面使用了const PINT b =&a,并且改变了a的值,但是奇怪的是,为啥没有报错,这是见了鬼吗(因为PINT是int *的别名嘛,所以const PINT b 应该是const int * b=&a,那不是应该报错嘛,可却没有报错,居然能够编译通过,有点不可思议啊)。其实这里就是陷阱了,这里不能这样按照常规的逻辑思维来看理解这个,我们应该把const PINT b=&a看成int * const b=&b,就能理解这里为啥不会报错了,哈哈哈。下面把PINT的位置调换到const的前面来,用法和这个一样。 1#include <stdio.h>2typedef int *PINT; 3 4int main(void) 5{+ l) y& [( A* y; w' z 6 int a=23;0 W) d% @! v# K, [ 7( A; Z" {2 \5 F) z 8 const PINT b=&a; 5 @6 l( I' U* f3 V0 ^: ?+ M 9 *b=8; 10" E: ^2 m0 I9 P 11 PINT const c=&a; //这个用法和上面的写法一样8 s9 f0 j/ B# C& z* ^, ` \ 12 *c=10; 133 m( a* R7 z0 c" I- s# M# X 14 return 0; 15 } 那看完这个,就会有网友会问了,那我要用typedef来实现const int * b=&a的用法,那怎样搞,这个的话,直接这样写,看下面的代码示例:( ^' c0 m3 p+ W7 W+ _6 o9 W 1#include <stdio.h>+ S4 M) x5 _' q25 y4 _ j u/ Q* u 3typedef const int * PINT;$ S' Z& |* i$ e3 i- U 4int main(void)' V) d; ?" h8 `# G# A 5{! w9 V" l8 c+ n3 ] 6int a=23; 7int c=90; 8PINT b=&a;//相当于const int * b 9*b=43;- i+ t( y6 C6 `" Z. j% S! h& ^" `: ? 10b=&c;4 o8 a$ P8 g0 k3 L% L6 d7 i& M 11 12) l q5 a. n4 j- d8 o/ o 13return 0; 14}+ O5 f- a; J/ n; B, F5 X' u4 L/ ]; ~! n 演示结果:
5 {* P7 Q, o! P# v* `1 R 二、define和typedef的区别: 我们在平时使用stm32的时候,也会经常使用define来进行宏定义,下面是常见的形式:
( i" y8 P: n1 \' h+ s7 j1 R1 p 那define与typedef有啥区别呢?下面主要讲两方面: (1):可以使用其他类型说明符对宏类型名进行扩展,但是对typedef定义的类型名不能这样做的: 1#include <stdio.h>4 w$ S+ k+ V( t0 z. c9 w7 t8 }9 E2 3#define haha int 4 5int main(void), J* z+ I% A9 R- T: E# b Z. X 6{ 7unsigned haha i; 87 x" {* W( V! [, C" E( K 9# q9 z0 C; x8 S/ b 10return 0;2 R, f& z( L/ ~' `4 n 11 }3 C9 _1 G' v' h1 V* g& f 演示结果:( v8 F, m/ ~; ~ . R2 M6 P/ ^$ L
6 @) h' k: W( Q0 X- i. v# ] 然后演示typedef: 1 #include <stdio.h>2 Q4 i1 h( A; ?! L" U2 3typedef int haha;8 y# s" Q/ ?) |9 m 4 5int main(void) 6{ 7unsigned haha i;/ a. }# F: ?" R. B/ M& } 8) Y! u3 n! L7 e: J" [% u. E, z1 r 9 10return 0; 11 } 0 e" \8 L/ v% Z* C5 k5 \) L ? 演示结果:
(2):在连续几个变量的声明中,用typedef定义的类型能够保证声明中所有的变量均为同一种数据类型,但是我们使用define就不能保证了,下面是演示示例:8 y# U8 S! h; }7 l! a 1#include <stdio.h>6 W4 o8 b* O% E& \, z g" \2 3# define haha int *2 A( g, |+ k3 R1 h; L3 Y/ s* W 4- E. I8 d& n6 P7 `. r% o! W* ]9 E 5int main(void)9 U+ r7 i& [( U; A' j0 s 6{ 7haha c,d; //这里就变成了不一样的结果了int *c,int d 8int a=9; 9 c=a;//这里实际应该是c=&a ' k8 ?4 ]% p3 a: t# u 10 d=a; 11% a" `9 m0 l( v+ F/ g/ ^7 ]$ a L 12 13 return 0;9 v$ Q% n. w0 i; M4 y0 ? 14 } 演示结果: ! N+ N. W9 t' U6 f( Y
下面我们使用typedef,就可以这样使用了哦: 1#include <stdio.h>( {8 ~3 E( q+ J, ?2 3typedef const int * haha;% S% f' U. w% u4 K, c0 k" N 4 5int main(void) 6{* S4 l# e9 X4 [9 ^, W" J3 ?9 M: x6 t 7 haha c,d; //这里就变成了不一样的结果了const int * haha, const int * d 8 int a=9; 9 c=&a; p0 D, W# P% K+ u 10 d=&a;0 b7 q! t2 P) @% u2 v1 g 11. T. P/ t/ K7 a- Q8 \3 B& |' l 12) |' d. I' U4 t7 e y; y0 T9 W 13return 0; 14 } 三、使用typedef来定义函数指针: 先从一个代码来分析: 1 #include <stdio.h>2 3 int add(int a, int b) {' ?, d9 X0 n/ X# B u; T 4 return a + b;8 [6 n l( {- x, j 5 } 6 7 typedef int (PTypeFun1)(int, int); // 声明一个函数类型 8 typedef int (*PTypeFun2)(int, int); // 声明一个函数指针类型# k$ |5 ?2 Q& t' x8 S 9 int (*padd)(int, int); // 传统形式,定义一个函数指针变量 10+ Y: B% |* \# w, `3 H 11int main() { 12 PTypeFun1 *pTypeAdd1 = add;$ l6 v N% c2 e! H. I 13 PTypeFun2 pTypeAdd2 = add; 14 padd = add;% \8 q6 l4 e p4 M 15 printf("pTypeAdd1(1, 2) is %d \n", pTypeAdd1(1, 2)); 16 printf("pTypeAdd2(1, 2) is %d \n", pTypeAdd2(1, 2));7 c) K+ T, Y# v1 T 17 printf(" padd(1, 2) is %d \n", padd(1, 2));( J/ v, j* |. J7 F5 ?7 z 18 return 0;8 k/ Y/ ^ G0 l3 T. q4 ~4 m! k 19} 其实这里也是给数据类型取了一个别名而已,但是当函数指针作为其它函数的参数,特别是作为返回值时,直接使用的函数指针无法编译,下面看示例: 1#include <stdio.h>2; O. ~" N& Q& a; l: v' f 3void FunA() {8 Z# x" S; E# U5 T4 @1 v! K+ s 4 printf("call FunA\n"); 5 }8 U" V' e" y) @3 @3 }* x) B" _ 6- }5 J( t0 h( I- b0 T 7 void FunB(int n) { 8 printf("call FunB. n is : %d\n", n);' r7 } p s5 @- ?6 \7 T$ u 9 }2 y4 f* t D" U 10 11 typedef void (*PtrFunA)();9 `/ P, ^6 t5 P4 {/ @ 12 typedef void (*PtrFunB)(int); 13$ v1 q! `6 R& M& {( x% V7 _2 w 14// 函数指针作为函数参数使用3 h' k0 {$ b6 S( c7 ^ @ 15 void usePtrFunA(PtrFunA p) { 16p();# {3 m* j9 ^- O5 O5 g 17 }, P. _, g' |" o 18 A& b" R3 q( I4 ]5 t3 X; d: F 19 void usePtrFunB(PtrFunB p, int n) {1 ?; J4 N. D5 r( L4 f$ z$ x 20p(n);6 }$ U, a1 K9 r2 b) r% Q: V 21 }4 Y5 P) O) D+ k1 a8 j8 ^ 22 23 //下面这种语法编译器已经无法识别了. [( k% Q+ {1 I7 f 24 (void (*PtrFunA)()) getPtrFunA2() { |! e! j2 i5 ?/ ]# W 25 return FunA; 26 } 27 28// 函数指针作为函数返回值使用 29 PtrFunA getPtrFunA() {3 ]$ \) F. Z( t J; S6 d) j 30 PtrFunA p = FunA; 31 return p;! b+ R) p% i- ]( W) O 32 }* X2 P& ^9 L- i* j& E 33 34 PtrFunB getPtrFunB() {3 B' R( [, X/ q6 L" w. | 35 PtrFunB p = FunB;" }; w! y B8 e( f7 L L, V3 } 36 return p;" |3 v, P' b. Y% [. y 37 }8 Y6 v5 \% E4 t N1 _ 38 39 int main() { 40 // 获取 FunA 函数的函数指针 41 PtrFunA a = getPtrFunA();) u' [+ B8 v4 w* K 42 // 使用 FunA 函数的函数指针 43 usePtrFunA(a); 442 t8 Z& P% e6 L( o 45// 获取 FunB 函数的函数指针; S6 d+ V) M7 k6 b* V 46PtrFunB b = getPtrFunB();' P# W3 T1 w z 47// 使用 FunB 函数的函数指针! c& K" T$ N% T 48usePtrFunB(b, 1); 49return 0;. o9 [* i1 i$ o' W9 h) x" X 50}& P% i( d# n9 ^ 4 M( t& _" u5 @9 W 四、总结: 以上是上面的关于typedef的几种比较不注意的地方使用方式总结,希望对你有用。 |
微信公众号
手机版