C++ void*解惑


最近遇到void *的問題無法解決,發現再也無法逃避了(以前都是采取悄悄繞過原則),於是我決定直面它。

在哪遇到了?

 


線程創建函數pthread_create()的最后一個參數void *arg,嗯?傳地址還是傳值?傳值好像有警告。

還有別的出現的地方呢

 

 

看memcpy(),返回值和參數都有void *,那又怎么傳呢?下面我們首先來說說void *是什么。

一:void *是什么?

C語言中,*類型就是指針類型。比如 int *p,double *q,雖然是不一樣的指針,但是大小卻一樣sizeof(p) == sizeof(q),其實很容易理解,因為他們都是同一種類型*類型的。C語言是強類型的語言。對類型的區分十分嚴格。那這兩個有什么不同點嗎?有,+1就不同了,看下面的圖:

 


也就是對於一個指針而言,如果我們在前面規定了它的類型。那就相當於決定了它的“跳躍力”。“跳躍力”就比如說上面圖中int跳了4個字節,但是double跳了8個字節。基於這樣的理解,我要對void *下定義了:

void * 是一個跳躍力未定的指針
二:跳躍力什么時候定?

這就是它的神奇之處了,我們可以自己控制在需要的時候將它實現為需要的類型。這樣的好處是:編程時候節約代碼,實現泛型編程。比如我們經常寫的排序算法,就可以這么寫:


#include <stdio.h>
#include <string.h>
static void Swap(char *vp1, char *vp2, int width)
{
char tmp;
if ( vp1 != vp2 ) {
while ( width-- ) {
tmp = *vp1;
*vp1++ = *vp2;
*vp2++ = tmp;
}
}
}
void BubbleSort(void *base, int n, int elem_size,
int (*compare)( void *, void * ))
{
int i, last, end = n - 1;
char *elem_addr1, *elem_addr2;
while (end > 0) {
last = 0;
for (i = 0; i < end; i++) {
elem_addr1 = (char *)base + i * elem_size;
elem_addr2 = (char *)base + (i + 1) * elem_size;
if (compare( elem_addr1, elem_addr2 ) > 0) {
Swap(elem_addr1, elem_addr2, elem_size);
last = i;
}
}
end = last;
}
}
int compare_int(void *elem1, void *elem2)
{
return (*(int *)elem1 - *(int *)elem2);
}
int compare_double(void *elem1, void *elem2)
{
return (*(double *)elem1 > *(double *)elem2) ? 1 : 0;
}
int main(int argc, char *argv[])
{
int num_int[8] = {8,7,6,5,4,3,2,1};
double num_double[8] = {8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1};
int i;
BubbleSort(num_int, 8, sizeof(int), compare_int);
for (i = 0; i < 8; i++) {
printf("%d ", num_int[i]);
}
printf("\n");
BubbleSort(num_double, 8, sizeof(double), compare_double);
for (i = 0; i < 8; i++) {
printf("%.1f ", num_double[i]);
}
printf("\n");
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

 


上面的compare_int和compare_double就是定它跳躍力的時候。

三:再來說memcpy

我們先來看下面這段代 碼:

#include<stdio.h>
#include<string.h>

struct stu{
int id;
int num;
};

#define LEN sizeof(struct stu) /*LEN 為stu的大小*/

int main(int argc,char *argv[])
{
struct stu stu1,stu2;
stu1.id = 2;
stu1.num = 3;

char str[LEN];

memcpy(str,&stu1,LEN); /*將stu1保存進str*/

memcpy(&stu2,str,LEN); /*將str轉換成stu2*/

printf("%d %d\n",stu2.id,stu2.num); /*訪問stu2仍然得到 2 和 3*/
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

 


說明:str 是一個char *類型的,但是&stu是一個struct stu *類型的,就像我們前面說的那樣,他們的“跳躍力”是不一樣的,但是memcpy之所以能將它們都接受,就是因為它的參數是(void *)類型的。在參數傳遞的時候包容萬象,全都接受,這才能體現人家是memcpy()嗎,mem是內存,肯定可以不非要按照某種具體類型處理,具體至於還想memcpy的內部怎么處理,看下面:

http://blog.csdn.net/yangbodong22011/article/details/53227560

四:總結

void *是一種指針類型,常用在函數參數、函數返回值中需要兼容不同指針類型的地方。我們可以將別的類型的指針無需強制類型轉換的賦值給void *類型。也可以將void *強制類型轉換成任何別的指針類型,至於強轉的類型是否合理,就需要我們程序員自己控制了。

#include<stdio.h>

int main(int argc,char *argv[])
{
int a = 2;
double b = 2.0;
void *c; //定義void *
int *p = &a;
c = p; //將int * 轉成void *,
double *q = (double *)c; //將void *轉成double *
printf("%.f\n",*q);

return 0;
}

 

oid * 為 “不確定類型指針”。
void *不可以解引用

(1)void *可以接受任何類型的賦值:
    任何類型的指針都可以直接賦值給void *型指針,無需進行強制類型轉換,相當於void *包含了其他類型的指針。

  
(2)void *可以賦值給任何類型的變量
但是需要進行強制轉換,應為void *的范圍較大,所以強制轉換,使其進行范圍縮小。

 


void *主要使用在函數里,可以接受其他類型的指針,讓函數使用起來更加便捷。

void * 1,不能解引用 2,+ - 運算


結果是不是正確呢?自己試一試吧~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM