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

C语言中的void关键字的用法

[复制链接]
gaosmile 发布时间:2020-9-4 20:55
1、简单认识一下void
    今天跟大家介绍的知识是C语言中的void关键字的用法,void在大部分小伙伴的程序中都只是用于函数无参数传入,或者无类型返回。
    然而我们平时所定义的变量都会有具体的类型,int,float,char等等,那是否有void类型的变量呢?大家可以动手实验一下,答案是:不行,编译会出错。

; L* |1 i( Z  X& a' ]8 Y
微信图片_20200904205249.png
6 f3 y1 S1 Y0 a! ^7 P; Y
    上图很明显编译器不允许定义void类型的变量,变量都是需要占用一定内存的,既然void表示无类型,编译器自然也就不知道该为其分配多大的内存,于是造成编译失败。
    虽然void不能直接修饰变量,但是其可以用于修饰指针的指向即无类型指针void*,无类型指针那就有意义了,无类型指针不是一定要指向无类型数据,而是可以指向任意类型的数据。

) d6 X* h8 j8 A
2、void * 基本操作
    大家其实在使用动态内存分配的使用就已经遇到了void *的使用,来我们一起看看如下几个标准函数的原型定义:
! R: \/ M) U+ y! a* E
微信图片_20200904205253.png
   
    上面这些函数都是与内存操作有关的函数,可能一些小伙伴使用过也不一定知道每个参数的具体类型是什么,这些void*部分的形参所传入的实参都是不需要进行强制类型转化的,所以根本就不需要关注传入指针所指向的具体类型,然而函数所返回的void *一般都需要通过强制类型转化为对应的具体类型,除非你最后所传递的变量也是void*类型。
参考void*用法:
1#include <stdio.h>
, z+ g1 v7 U- b. i- Q. {1 u3 o 2#include <stdlib.h>
( h, a' V1 V8 c 3#include <malloc.h>
% z9 y( {, R% v- [: d. w 4
6 [$ c# v6 `# @8 J. w. R6 K 5#define NUM 103 v" v7 I/ Y6 N, C
6/*************************************) i* N8 J& j% m7 \+ C
7 * Fuction:了解一下void*的使用 , E) P' m0 Y2 ]0 @
8 * Author : (公众号:最后一个bug) ! _) W: G  M. Y3 o
9 *************************************/' \& c& ~  j9 W! k- d+ r* w
10int main(int argc, char *argv[]) {9 l8 A  q' v0 z6 y' I
11    int *p1 = (int *)malloc(NUM*sizeof(int));
! M) b: Y, n# @8 o) W( W! ?12    int *p2 = (int *)malloc(NUM*sizeof(int)); 7 _- R9 w6 N) G# Z7 \
13    int  i = 0;1 o. o! q! p% }/ J% c/ N
14
8 _8 P# }+ v& I4 U15    //初始化p1
9 e* a+ N! s2 Z. u1 M) e8 s5 e16    for(i = 0;i < NUM;i++) # e3 H4 x& D9 x
17    {
% A3 ]9 s  r% K18        *(p1+i) = i;- Y( f1 V. w  M- Q1 m1 ]6 I% \+ P
19    }+ |( c3 k/ Y- M8 c: f- B
20    //进行内存copy   p. {7 j1 B% i" e) G
21    memcpy(p2,p1,NUM*sizeof(int));2 {- q2 n  z/ z8 ?, h2 t' g
22
! F( j7 B; k+ J; L6 D2 k23    //输出另外一个分配的内存
/ n  M# F% Y( U+ @7 C4 A24    for(i = 0;i < NUM;i++)
2 J9 r) \. F7 o9 x# p- ^5 X25    {
9 S) f* E# z+ \5 a/ D  {26       printf("%d,",*(p2+i)); 1 V/ l7 F: y  _! @/ k0 C6 ]
27    }   
: H+ t: B: M$ }8 p28    //释放内存
6 R& o* b& X" y# S/ G2 y) E0 N# w29    free(p1);# B1 F& ~9 Q3 W
30    free(p2);
( N4 b8 ^7 d' i. T31    return 0;
& r, \0 b! B% w1 a. f32}
运行结果:
微信图片_20200904205256.png

& N  L7 l0 u$ h
3、使用void * 实现无类型数据封装
    为了保持文章的完整性,也许这里才是作者最想跟大家介绍的,void*既然如此的灵活一定大有用处,如果仅仅只是用来简单的传递参数似乎有点大材小用,我们得把其用到上层的软件设计上来。
    在一些项目中经常看到有小伙伴把数据类型转来转去,甚至有时候为了一个数据类型的变化还得重新写一个仅仅数据类型不同的函数,这样的代码上万行代码指日可待,按下面我们以一个例子来跟大家介绍一种办法能够减少数据类型变化所带来的程序重复代码的增加。
参考实例:
. Y' y% m9 g5 y- H
1#include <stdio.h>
2 U$ N5 @5 o: f 2#include <stdlib.h>5 K  t# w' O6 P
3/********************************** . G5 Z# B3 C# h. v- k, x
4 * Fuction : add3 |& T4 F0 ?6 x( d( _
5 * descir :  加法的相关数据及处理办法
, N) c9 b1 w/ B$ \/ i 6 * Author : (公众号:最后一个bug)$ S3 _8 Y; i! K/ E- [
7 **********************************/ 4 Q; f3 P9 ^6 q$ X/ @
8typedef struct _tag_Add  @7 y% S8 C7 X7 n0 q. }* b
9{& i1 c! K1 V! I
10    int a;
# \3 J" \+ Y& s! Q8 ?11    int b;. U7 F% H: Y5 B! b
12    int result;; ]0 P: I8 J: _- ]3 s, p" Q
13}sAdd;
0 {# u% _( N9 Q( A. {7 Q146 E* `* W. F% O
15void Add(void *param)* w: z* w3 W& X0 z7 p
16{, V1 V' T. R, L6 v% Z- @8 x; T. z
17    sAdd *p = (sAdd *) param;3 R( S& w5 ]" [( @: U& U3 U3 G
18    p->result = p->a + p->b;
1 C( s- E6 g5 N; j. _  z2 {& S19}
' r# X9 A% H. I; {' Y20/**********************************
! N8 h' v1 m( I! m+ N: g" j21 * Fuction : add
8 |9 K6 I* B/ b, v, X! D! Z  [22 * descir :  乘法的相关数据及处理办法
  D4 Q/ `2 d: U% |23 * Author : (公众号:最后一个bug)
; G2 c! x. v$ F/ z' }( ]24 **********************************/
$ Y( Y9 Q) R+ R! L; b/ \25typedef struct _tag_Mul: ~! b( S2 ]- p5 z; W
26{5 [- P; |4 x" f9 g, }! E
27    float a;/ H& j$ a- @2 Z2 O
28    float b;3 ^+ v' A6 C3 H# F/ k, U
29    float result;
% s* A: l7 ^6 }4 G' h0 ?, t30}sMul;
$ y2 N8 G; r8 W  p31/ M% X' B  T% e2 S. ]# I5 {
32void Mul(void *param)
' b% k( P: N, `33{
7 h- z/ Y5 Z0 H6 S/ I34    sMul *p = (sMul *) param;, _( a7 v: @/ @
35    p->result = p->a * p->b;/ [8 r0 H+ ]5 B& J- R6 X
36}
8 t# E% ~; h6 C2 P- `37
/ H  O5 W+ P& Z! }7 r- Y) k' z# `38/************************************* # B( H+ ~2 h& R4 n  k" W4 T3 C
39 * Fuction : sCal/ ]: B- U5 S: a* h; d- D
40 * descir :  公共的调用接口
# t2 K; c# \+ z1 M* }; T41 * Author : (公众号:最后一个bug)! G* h1 j5 O! [* x
42 ************************************/ ' u3 l5 o8 @) ^
43void sCal(void *param,void *fuc)
5 ~7 W) z- {2 t; Y2 B" I44{
$ ^; N, C! |3 ~0 c, {4 N45    ((void (*)(void*))fuc)(param);
8 ?, ~' {( `- K# m0 z$ R" W- e46}- Z5 Q! x! p6 |
47& ~1 ?0 l6 I  t4 H; q! m' U
48/********************************** 5 J5 M1 W) s  d0 M
49 * Fuction : main( `  z* V4 b( s+ A
50 * descir : 应用接口实例 $ @6 {% ^1 f) `& C
51 * Author : (公众号:最后一个bug); `3 T/ t& F" g+ r- v9 Q! X
52 **********************************/  - e0 K. T; k3 b8 k
53int main(void)5 Q  C8 s' S+ P% _8 l5 K5 e7 i- u
54{
" O6 {" M1 t- v& m8 W% O1 N+ y55    sAdd stAdd;) n# _& }, T7 s% n
56    sMul stMul;( [: R5 V2 w: f
570 y* g8 S  d8 D$ v/ @
58    //数据初始化
: b9 `/ d/ P  a, l7 z0 \59    stAdd.a = 10;
4 @' Y- v) |/ f& i60    stAdd.b = 20;
4 Q! o, C% X, I+ i5 C/ I( J61. a) I4 o( g- G- r! b
62    stMul.a = 5;6 }9 _  I9 |. X0 C# Y* x2 X0 Y* X
63    stMul.b = 5;
+ F/ k7 P1 o  ]) A* k9 ^64    //接口直接用 ' e: d; H1 k( z3 f: }
65    sCal(&stAdd,Add);
* D8 ^- r$ b$ c) X1 C% Q66    sCal(&stMul,Mul);8 V3 L% O; v' ?) J* }1 F. l
67    //对应的输出 2 w# X* y6 a8 l6 n2 N
68    printf("a + b = %d\n",stAdd.result);
( j9 i/ ?" Q0 H1 s/ \$ W69    printf("a * b = %f\n",stMul.result);
/ W8 e( R+ g- G9 t70    printf("公众号:最后一个bug\n");, r& b4 q0 h& |' v. y# k
71    return 0;
! Y5 S7 I( F8 v1 R; O9 v6 c" m72 } . y0 h6 z  x; C( F# h5 \8 e
运行结果:
微信图片_20200904205259.png
分析一下:

& U7 z" k2 }9 S! @4 A
    上面的例子可能还是无法完全彰显void*的强悍之处了,不过其主要的作用就是为了隐藏数据类型,大家也可以理解为一种数据类型的抽象处理,这也是面向对象编程的一种体现。

4 a0 r! M1 [. q2 R0 x6 H
4、最后小结
7 B2 k# T; a# n' w, ~
    对于void这个关键字的使用bug菌就先讲这么多吧!大家一定要记得对于一些编程技巧一定要尝试着去使用,可能达到项目目标的方式有很多种,但是一些好的设计不仅仅会让你的代码增色不少,同时也会让同事们觉得你是一个喜欢专研技术的人。
9 b3 f6 [: v5 s# \* @* @
赞 收藏 1 评论1 发布时间:2020-9-4 20:55

举报

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