(void * )无符号类型指针

引入

学过Linux操作系统的朋友们都知道线程创建相关的知识,最近小帆在学习这方面知识时,遇到了指针方面的问题,下面我们来一起过一遍历程。

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
//Thread1执行函数
void *thread_1(void *arg)
{
	int rec = 0;

	sleep(1);
	rec = (int)(arg);
	printf("new thread1 arg = %d\n", rec);
	return NULL;
}
//Thread2执行函数
void *thread_2(void *arg)
{
	int rec = 0;

	sleep(1);
	rec = *((int *)(arg));
	printf("new thread2 arg = %d\n", rec);
	return NULL;
}

int main(int argc, char *argv[])
{
	pthread_t tid1, tid2;//定义tid1,tid2
	int test = 100;//定义一个整形变量,赋值为100

	/*创建两个线程*/
	pthread_create(&tid1, NULL, thread_1, (void *)test);
	pthread_create(&tid1, NULL, thread_2, (void *)(&test));
	while(1);
	return 0;
}

历程编写思路

第一步

搭好main函数框架,添加while(1)控制主进程处于运行状态,在主进程(即,main函数)中调用pthread_create()函数创建两个线程后,第一个参数需要传入线程标识符地址,此时引出第二步。

int main(int argc, char *argv[])
{
	/*创建两个线程*/
	pthread_create();
	pthread_create();
	while(1);
	return 0;
}

第二步

声明两个pthread_t 类型的变量tid1和tid2。这里小帆有一个问题。此处的tid1,为何不类似于进程创建时的pid,需要通过接收fork()函数返回值进行赋值,后使用,而是声明完直接被当做实参传入pthread_create()函数使用;根据老师的讲解得知:C语言中,声明一个变量后,若不对其赋初值,则系统会赋予它一个随机数,随机数所在的地址是唯一的,故而这里的线程创建函数通过&tid,把这个唯一的地址值当做线程标识符地址,实现唯一性。此种用法,让身为小白的小帆我佩服的五体投地!

pthread_t tid1, tid2;//定义tid1,tid2
pthread_create(&tid1);
pthread_create(&tid1);

第三步

参数二为属性设置,暂不深究,姑且设置为NULL;参数三传入线程执行函数的入口地址,此时便去定义各线程的执行函数,即,thread1和thread2,注意定义的格式void *类型,传入参数也是void * 类型。

	pthread_create(&tid1, NULL, thread_1);
	pthread_create(&tid1, NULL, thread_2);
void *thread1(void *arg)
{
	
	return NULL;
}
void *thread2(void *arg)
{
	
	return NULL;
}

第四步

重点来了!参数四——传给新线程执行函数参数,且为(void *)类型。
1.定义一个整形变量

int test = 100;//定义一个整形变量,赋值为100

2.将变量进行强转后,放入参数四的位置

pthread_create(&tid1, NULL, thread_1, (void *)test);
pthread_create(&tid1, NULL, thread_2, (void *)(&test));

void * 是一个无类型的指针,可以指向任意数据类型;
先分析test:
test是一个值为100的整形变量;
(void *) test则是将一个整形变量强转为指针变量,test中存放的数值100此时就不再是整形数据100,而是地址100,因为内存地址使用的是十六进制数,所以打印到屏幕就是十六进制数的一百(0X64),运行截图如下;
在这里插入图片描述
当test被传入线程一的执行函数后,我们想对其进行打印,这里的打印是打印整形数据100,此时又涉及到强制类型转换,代码补全如下:

//Thread1执行函数
void *thread_1(void *arg)
{
	int rec = 0;

	sleep(1);
	rec = (int)(arg);
	printf("new thread1 arg = %d\n", rec);
	return NULL;
}

定义一个int类型的变量rec,显示赋值为0,延时一秒后,强制类型转换后输出。
此时的test早已赋给arg,arg则代表一个指针变量,想要变回整形变量,就用(int)强转,强转之后arg就变成了一个整形变量,其所存放的内容也由地址转换为了整形的数据,此时便可赋值给rec,并打印输出,效果图如下:
在这里插入图片描述
接下来分析&test:
&test,初步理解是取test的地址,也就是取存放整形数据100的地址;
深入理解则等同于一个指向存放整形数据100地址的int类型指针;
(void *)(&test)则将&test从一个int类型的指针强转为无类型的指针,为什么要转?因为void * 类型的指针可以指向任意数据类型,具有通用性,很多时候不确定传入的参数是什么类型,所以统一转为void * 类型,传入,后转回使用;
此时,我们也要对其进行打印,这里的打印也是打印整形数据100,此时还是涉及到强制类型转换,代码补全如下:

//Thread2执行函数
void *thread_2(void *arg)
{
	int rec = 0;

	sleep(1);
	rec = *((int *)(arg));
	printf("new thread2 arg = %d\n", rec);
	return NULL;
}

直接看转换的代码

rec = *((int *)(arg));

arg是传入的&test,也就是一个指针,还是个无类型的指针;
它之前是个int类型的指针,所以要想取其值且付给一个int类型的变量,就需要先把arg由无符号类型指针转换为int类型的指针,再通过“* p” 的方式访问存放整形数据100的内存单元,并将其取出,思路剖析如下:
1.(int *)(arg)
2. *((int *)(arg))
3.rec = *((int *)(arg))
此时再打印rec的值就是整形数据100,效果图如下:
在这里插入图片描述

总结

变量被强转为指针后,变量所存储的内容也就成为了指针类型的数据,即,地址。
而“&变量”本身就是个地址,强转之后还是地址,不影响该地址下的存放的数据,拿int类型的指针来举例:
int * a = 100;
a 是存放整形数据100的地址,假设是0X1234;
*a是告诉编译器取出0X1234内存放的数据,并按照int类型数据存储的方式解析出它的值;
历程中&test也是个地址,其中存放的数据100也是整形的,那么a = &test,可以理解为&test就是一个int类型的指针,指向int类型的数据,且取其值的方式 * a = (&test) =100;
因为&test之前被转换为void * 类型的指针,所以在取值之前需要强转为原来的类型,这里是int * 类型,所以
((int *)(&test));
void * 无类型指针,可以指向任意类型的数据,所以历程中将int类型的指针强转为void类型的指针也是可以的,其地址内存放的数据类型不会发生改变,需要的时候,再将其转换回来,具有较强的通用性。

结束

由于小帆在指针方面也是个小白,只能站在初学者的角度去理解,此处用于笔记整理,所以内容仅供参考。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值