是否可以在C编程语言中取消引用void指针而不使用类型转换?
此外,有没有任何方法可以概括一个可以接收指针并将其存储在void指针中的函数,并且通过使用该void指针,我们可以创建一个通用函数吗?
例如:
void abc(void *a, int b)
{
if(b==1)
printf("%d",*(int*)a); // If integer pointer is received
else if(b==2)
printf("%c",*(char*)a); // If character pointer is received
else if(b==3)
printf("%f",*(float*)a); // If float pointer is received
}
我想在不使用if-else语句的情况下使这个函数变得通用 - 这可能吗?
此外,如果有很好的互联网文章解释了无效指针的概念,那么如果你能提供这些网址将是有益的。
此外,是否可以使用void指针进行指针运算?
答案 0 :(得分:92)
是否可以在C编程语言中取消引用void指针而不使用类型转换...
不,void
表示缺少类型,这不是您可以取消引用或分配的内容。
是否有任何方法可以概括一个可以接收指针并将其存储在void指针中的函数,并且通过使用该void指针,我们可以创建一个通用函数。
您不能以便携方式取消引用它,因为它可能无法正确对齐。这可能是ARM等某些体系结构的问题,其中指向数据类型的指针必须在数据类型大小的边界处对齐(例如,指向32位整数的指针必须在4字节边界处对齐才能被解除引用)。 / p>
例如,从uint16_t
阅读void*
:
/* may receive wrong value if ptr is not 2-byte aligned */
uint16_t value = *(uint16_t*)ptr;
/* portable way of reading a little-endian value */
uint16_t value = *(uint8_t*)ptr
| ((*((uint8_t*)ptr+1))<<8);
此外,是否可能使用void指针进行指针算法......
由于指针下面没有具体的值,因此指针void
上的指针运算是不可能的。
void* p = ...
void *p2 = p + 1; /* what exactly is the size of void?? */
答案 1 :(得分:28)
在C中,void *
可以转换为指向不同类型对象的指针,而无需显式转换:
void abc(void *a, int b)
{
int *test = a;
/* ... */
但这对于以更通用的方式编写函数没有帮助。
您不能取消引用void *
并将其转换为不同的指针类型,因为取消引用指针正在获取指向对象的值。裸void
不是有效类型,因此无法对void *
进行解除。
指针算法是指将指针值改变为指向对象的sizeof
的倍数。同样,因为void
不是真正的类型,sizeof(void)
没有意义所以指针算法在void *
上无效。 (某些实现允许使用char *
的等效指针算法。)
答案 2 :(得分:15)
你应该知道在C中,与Java或C#不同,绝对不可能成功地“猜测”void *指针指向的对象类型。类似于“getClass()”的东西根本不存在,因为这些信息无处可寻。因此,您正在寻找的那种“通用”总是带有明确的元信息,例如示例中的“int b”或printf函数族中的格式字符串。
答案 3 :(得分:6)
void指针称为通用指针,可以引用任何数据类型的变量。
答案 4 :(得分:6)
到目前为止,我对void指针的理解如下:
当使用关键字void声明指针变量时 - 它变为通用指针变量。可以将任何数据类型(char,int,float等)的任何变量的地址分配给void指针变量。
main()
{
int *p;
void *vp;
vp=p;
}
由于其他数据类型指针可以分配给void指针,所以我在absolut_value(下面显示的代码)函数中使用它。为了起到一般作用。
#include<stdio.h>
void absolute_value ( void *j) // works if used float, obviously it must work but thats not my interest here.
{
if ( *j < 0 )
*j = *j * (-1);
}
int main()
{
int i = 40;
float f = -40;
printf("print intiger i = %d \n",i);
printf("print float f = %f \n",f);
absolute_value(&i);
absolute_value(&f);
printf("print intiger i = %d \n",i);
printf("print float f = %f \n",f);
return 0;
}
但是我得到了错误,所以我开始知道我对无效指针的理解是不正确的:(。所以现在我将走向收集点为什么会这样。
我需要在void指针上更多地了解的是。
我们需要对void指针变量进行类型转换以取消引用它。这是因为void指针没有与之关联的数据类型。编译器无法知道(或猜测?)void指针指向的数据类型。因此,为了获取void指针所指向的数据,我们使用在void指针位置内保存的正确数据类型对其进行类型转换。
void main()
{
int a=10;
float b=35.75;
void *ptr; // Declaring a void pointer
ptr=&a; // Assigning address of integer to void pointer.
printf("The value of integer variable is= %d",*( (int*) ptr) );// (int*)ptr - is used for type casting. Where as *((int*)ptr) dereferences the typecasted void pointer variable.
ptr=&b; // Assigning address of float to void pointer.
printf("The value of float variable is= %f",*( (float*) ptr) );
}
如果程序员不确定最终用户输入的数据的数据类型,则void指针非常有用。在这种情况下,程序员可以使用void指针指向未知数据类型的位置。可以以要求用户通知数据类型的方式设置程序,并且可以根据用户输入的信息执行类型转换。下面给出了一个代码段。
void funct(void *a, int z)
{
if(z==1)
printf("%d",*(int*)a); // If user inputs 1, then he means the data is an integer and type casting is done accordingly.
else if(z==2)
printf("%c",*(char*)a); // Typecasting for character pointer.
else if(z==3)
printf("%f",*(float*)a); // Typecasting for float pointer
}
关于void指针,你应该记住的另一个重点是 - 指针算术不能在void指针中执行。
void *ptr;
int a;
ptr=&a;
ptr++; // This statement is invalid and will result in an error because 'ptr' is a void pointer variable.
所以现在我明白了我的错误。我正在纠正同样的问题。
参考文献:
http://www.antoarts.com/void-pointers-in-c/
http://www.circuitstoday.com/void-pointers-in-c
新代码如下所示。
#include<stdio.h>
#define INT 1
#define FLOAT 2
void absolute_value ( void *j, int *n)
{
if ( *n == INT) {
if ( *((int*)j) < 0 )
*((int*)j) = *((int*)j) * (-1);
}
if ( *n == FLOAT ) {
if ( *((float*)j) < 0 )
*((float*)j) = *((float*)j) * (-1);
}
}
int main()
{
int i = 0,n=0;
float f = 0;
printf("Press 1 to enter integer or 2 got float then enter the value to get absolute value\n");
scanf("%d",&n);
printf("\n");
if( n == 1) {
scanf("%d",&i);
printf("value entered before absolute function exec = %d \n",i);
absolute_value(&i,&n);
printf("value entered after absolute function exec = %d \n",i);
}
if( n == 2) {
scanf("%f",&f);
printf("value entered before absolute function exec = %f \n",f);
absolute_value(&f,&n);
printf("value entered after absolute function exec = %f \n",f);
}
else
printf("unknown entry try again\n");
return 0;
}
谢谢,
答案 5 :(得分:2)
不,这是不可能的。取消引用的值应该具有什么类型?
答案 6 :(得分:2)
void abc(void *a, int b) {
char *format[] = {"%d", "%c", "%f"};
printf(format[b-1], a);
}
答案 7 :(得分:1)
我想让这个功能变得通用, 不使用ifs;有可能吗?
我看到的唯一简单方法是使用重载..这在C编程语言AFAIK中是不可用的。
您是否考虑过针对您的程序的C ++编程语言?或者是否有禁止其使用的限制?
答案 8 :(得分:0)
您可以轻松打印空白打印机
int p=15;
void *q;
q=&p;
printf("%d",*((int*)q));
答案 9 :(得分:0)
因为C是静态类型的强类型语言,所以必须在编译之前确定变量的类型。当您尝试在C中模拟泛型时,您最终会尝试再次重写C ++,因此最好使用C ++。
答案 10 :(得分:0)
void指针是一个通用指针。任何变量的任何数据类型的地址都可以赋给void指针。
int a = 10;
float b = 3.14;
void *ptr;
ptr = &a;
printf( "data is %d " , *((int *)ptr));
//(int *)ptr used for typecasting dereferencing as int
ptr = &b;
printf( "data is %f " , *((float *)ptr));
//(float *)ptr used for typecasting dereferencing as float
答案 11 :(得分:0)
以下是void
指针的简要指针:https://www.learncpp.com/cpp-tutorial/613-void-pointers/
6.13 —空指针
由于void指针不知道其指向的对象类型,因此无法直接取消引用!相反,必须先将void指针显式转换为其他类型的指针,然后再将其取消引用。
如果void指针不知道它指向的是什么,我们如何知道将其强制转换为什么?最终,这取决于您。
无效指针杂项
不可能对void指针进行指针算术运算。这是因为指针算法要求指针知道其指向的对象大小,因此可以适当地增加或减少指针。
假设机器的内存是字节可寻址的,并且不需要对齐的访问,则解释void*
的最通用和原子性(最接近机器级别的表示形式)是指向一个字节的指针,uint8_t*
。例如,将void*
强制转换为uint8_t*
可以打印出从该地址开始的前1/2/4/8 /许多您想要的字节,但是您可以什么也没做。
uint8_t* byte_p = (uint8_t*)p;
for (uint8_t* i = byte_p; i < byte_p + 8; i++) {
printf("%x ",*i);
}
答案 12 :(得分:0)
您不能在不指定指针类型的情况下取消引用指针,因为不同的数据类型在内存中具有不同的大小,即int为4字节,char为1字节。
答案 13 :(得分:0)
无效指针是没有相关数据类型的指针。无效指针可以保存任何类型的地址,并且可以被类型转换为任何类型。但是,不能直接取消引用空指针。
int x = 1;
void *p1;
p1 = &x;
cout << *p1 << endl; // this will give error
cout << (int *)(*p) << endl; // this is valid
答案 14 :(得分:-1)
从根本上讲,在C语言中,“类型”是一种解释内存中字节的方法。例如下面的代码
struct Point {
int x;
int y;
};
int main() {
struct Point p;
p.x = 0;
p.y = 0;
}
说“当我运行main时,我想分配4(整数大小)+ 4(整数大小)= 8(总字节数)的内存。当我将'.x'作为左值写入具有类型标签指向编译时,从指针的内存位置获取数据再加上四个字节。给返回值指定编译时标签“ int”。
运行时在计算机内部,您的“点”结构如下所示:
00000000 00000000 00000000 00000000 00000000 00000000 00000000
这是您的void*
数据类型的样子:(假设是32位计算机)
10001010 11111001 00010010 11000101
答案 15 :(得分:-2)
这不起作用,但void *可以帮助定义函数的通用指针并将其作为参数传递给另一个函数(类似于Java中的回调),或者将其定义为类似于oop的结构。