被同學用void給我瘋狂秀了一波技術

沃愛單片機 發佈 2024-03-11T01:47:11.564798+00:00

1、簡單認識一下void今天給大家介紹的是C語言中的void關鍵字的用法。void在大部分小夥伴的程序中都只是用於函數無參數傳入,或者無類型返回。然而,我們平時所定義的變量都會有具體的類型,int、float、char等。那麼,是否有void類型的變量呢?

1、簡單認識一下void

今天給大家介紹的是C語言中的void關鍵字的用法。void在大部分小夥伴的程序中都只是用於函數無參數傳入,或者無類型返回。

然而,我們平時所定義的變量都會有具體的類型,int、float、char等。那麼,是否有void類型的變量呢?大家可以動手實驗一下,答案是不行,編譯會出錯。

上圖很明顯編譯器不允許定義void類型的變量,變量都是需要占用一定內存的,既然void表示無類型,編譯器自然也就不知道該為其分配多大的內存,於是造成編譯失敗。

雖然void不能直接修飾變量,但其可以用於修飾指針的指向即無類型指針void*,無類型指針那就有意義了,無類型指針不是一定要指向無類型數據,而是可以指向任意類型的數據。

2、void * 基本操作

其實,大家在動態內存分配的使用中就已經遇到了void *,下面我們一起看看如下幾個標準函數的原型定義:

上面這些函數都是與內存操作有關的函數,可能一些小夥伴使用過也不一定知道每個參數的具體類型是什麼,這些void*部分的形參所傳入的實參都是不需要進行強制類型轉化的,所以根本就不需要關注傳入指針所指向的具體類型。

然而,函數所返回的void *一般都需要通過強制類型轉化為對應的具體類型,除非你最後所傳遞的變量也是void*類型。

參考void*用法:

 1#include <stdio.h>
 2#include <stdlib.h>
 3#include <malloc.h> 
 4
 5#define NUM 10
 6/*************************************
 7 * Fuction:了解一下void*的使用 
 8 * Author :  
 9 *************************************/
10int main(int argc, char *argv[]) {
11 int *p1 = (int *)malloc(NUM*sizeof(int)); 
12 int *p2 = (int *)malloc(NUM*sizeof(int)); 
13 int i = 0;
14
15 //初始化p1 
16 for(i = 0;i < NUM;i++) 
17 {
18 *(p1+i) = i;
19 }
20 //進行內存copy 
21 memcpy(p2,p1,NUM*sizeof(int));
22
23 //輸出另外一個分配的內存 
24 for(i = 0;i < NUM;i++) 
25 {
26 printf("%d,",*(p2+i)); 
27 } 
28 //釋放內存 
29 free(p1);
30 free(p2);
31 return 0;
32}

運行結果:

3、使用void * 實現無類型數據封裝

為了保持文章的完整性,也許這裡才是作者最想跟大家介紹的,void*既然如此的靈活一定大有用處,如果僅僅只是用來簡單的傳遞參數似乎有點大材小用,我們得把其用到上層的軟體設計上來。

在一些項目中經常看到有小夥伴把數據類型轉來轉去,甚至有時候為了一個數據類型的變化還得重新寫一個僅僅數據類型不同的函數,這樣的代碼上萬行代碼指日可待,按下面我們以一個例子來跟大家介紹一種辦法能夠減少數據類型變化所帶來的程序重複代碼的增加。

參考實例:


 1#include <stdio.h>
 2#include <stdlib.h>
 3/********************************** 
 4 * Fuction : add
 5 * descir : 加法的相關數據及處理辦法 
 6 * Author : 
 7 **********************************/ 
 8typedef struct _tag_Add
 9{
10 int a;
11 int b;
12 int result;
13}sAdd;
14
15void Add(void *param)
16{
17 sAdd *p = (sAdd *) param;
18 p->result = p->a + p->b;
19}
20/********************************** 
21 * Fuction : add
22 * descir : 乘法的相關數據及處理辦法 
23 * Author : 
24 **********************************/ 
25typedef struct _tag_Mul
26{
27 float a;
28 float b;
29 float result;
30}sMul;
31
32void Mul(void *param)
33{
34 sMul *p = (sMul *) param;
35 p->result = p->a * p->b;
36}
37
38/************************************* 
39 * Fuction : sCal
40 * descir : 公共的調用接口 
41 * Author :
42 ************************************/ 
43void sCal(void *param,void *fuc)
44{
45 ((void (*)(void*))fuc)(param);
46}
47
48/********************************** 
49 * Fuction : main
50 * descir : 應用接口實例 
51 * Author : 
52 **********************************/ 
53int main(void)
54{
55 sAdd stAdd;
56 sMul stMul;
57
58 //數據初始化 
59 stAdd.a = 10;
60 stAdd.b = 20;
61
62 stMul.a = 5;
63 stMul.b = 5;
64 //接口直接用 
65 sCal(&stAdd,Add);
66 sCal(&stMul,Mul);
67 //對應的輸出 
68 printf("a + b = %d\n",stAdd.result);
69 printf("a * b = %f\n",stMul.result);
70 return 0;
71 } 

運行結果:

分析一下:

上面的例子可能還是無法完全彰顯void*的強悍之處了,不過,其主要的作用就是為了隱藏數據類型,大家也可以理解為一種數據類型的抽象處理,這也是面向對象編程的一種體現。

4、小結

對於void關鍵字的使用,今天就先講這麼多。大家切記,對於一些編程一定要嘗試著去使用,可能達到項目目標的方式有很多種,但一些好的設計不僅會讓你的代碼增色不少,同時也會讓同事們覺得你是一個喜歡專研技術的人。

END

關鍵字: