繁体   English   中英

C编程中void指针的概念

[英]Concept of void pointer in C programming

在 C 编程语言中,是否可以在不进行类型转换的情况下取消引用 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 语句 - 这可能吗?

此外,如果有很好的互联网文章解释了空指针的概念,那么如果您能提供 URL,那将是有益的。

另外,是否可以使用空指针进行指针运算?

是否可以在 C 编程语言中不进行类型转换的情况下取消引用 void 指针...

不, void表示没有类型,它不是您可以取消引用或分配的东西。

是否有任何方法可以泛化一个可以接收指针并将其存储在 void 指针中的函数,并且通过使用该 void 指针,我们可以创建一个泛化函数..

您不能只是以可移植的方式取消引用它,因为它可能没有正确对齐。 这可能是一些架构上的问题,例如 ARM,其中指向数据类型的指针必须在数据类型大小的边界对齐(例如,指向 32 位整数的指针必须在 4 字节边界对齐才能取消引用)。

例如,从void*读取uint16_t

/* 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* p = ...
void *p2 = p + 1; /* what exactly is the size of void?? */

在 C 中,可以将void *转换为指向不同类型对象的指针,而无需显式转换:

void abc(void *a, int b)
{
    int *test = a;
    /* ... */

但是,这无助于以更通用的方式编写函数。

您不能取消引用void *并将其转换为不同的指针类型,因为取消引用指针是获取指向对象的值。 void不是有效类型,因此不可能取消对void *引用。

指针算术是关于将指针值更改为指向对象sizeof的倍数。 同样,因为void不是真正的类型,所以sizeof(void)没有意义,所以指针算术在void *void * (一些实现允许它,使用char *的等效指针算法。)

您应该知道,在 C 中,与 Java 或 C# 不同,绝对不可能成功“猜测” void*指针指向的对象类型。 getClass()类似的东西根本不存在,因为找不到此信息。 出于这个原因,您正在寻找的那种“通用”总是带有显式元信息,例如您的示例中的int bprintf系列函数中的格式字符串。

void 指针被称为泛型指针,它可以指向任何数据类型的变量。

到目前为止,我对 void 指针的理解如下。

当使用关键字 void 声明指针变量时,它变成了通用指针变量。 任何数据类型(char、int、float 等)的任何变量的地址都可以分配给 void 指针变量。

main()
{
    int *p;

    void *vp;

    vp=p;
} 

由于其他数据类型的指针可以分配给void指针,所以我在absolut_value(如下所示的代码)函数中使用了它。 做一个通用的功能。

我试图编写一个简单的 C 代码,它以整数或浮点数作为参数,并尝试使其为 +ve,如果为负数。 我写了以下代码,

#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 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;
}   

谢谢,

不,这是不可能的。 解除引用的值应该具有什么类型?

void abc(void *a, int b) {
  char *format[] = {"%d", "%c", "%f"};
  printf(format[b-1], a);
}

以下是关于void指针的简要说明: https : //www.learncpp.com/cpp-tutorial/613-void-pointers/

6.13 — 空指针

因为void指针不知道它指向的是什么类型的对象,所以不能直接解引用! 相反,在取消引用之前,必须首先将 void 指针显式转换为另一种指针类型。

如果一个 void 指针不知道它指向什么,我们怎么知道将它转换为什么? 最终,这取决于您来跟踪。

空指针杂项

不可能对空指针进行指针运算。 这是因为指针运算需要指针知道它指向的对象大小,因此它可以适当地增加或减少指针。

假设机器的内存是字节可寻址的并且不需要对齐访问,解释void*的最通用和原子(最接近机器级表示)的方法是作为指向字节的uint8_t* 例如,将void* uint8_t*转换为uint8_t*将允许您打印出从该地址开始的前 1/2/4/8/however-many-you-desire 字节,但您不能做很多其他事情。

uint8_t* byte_p = (uint8_t*)p;
for (uint8_t* i = byte_p; i < byte_p + 8; i++) {
  printf("%x ",*i);
}

我想让这个函数通用,不使用 ifs; 是否有可能?

我看到的唯一简单方法是使用重载 .. 这在 C 编程语言 AFAIK 中不可用。

您是否考虑过 C++ 编程语言? 或者是否有任何限制禁止其使用?

您可以轻松打印空白打印机

int p=15;
void *q;
q=&p;
printf("%d",*((int*)q));

由于 C 是静态类型的强类型语言,因此必须在编译之前确定变量的类型。 当您尝试在 C 中模拟泛型时,您最终将再次尝试重写 C++,因此最好改用 C++。

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

您不能在不指定类型的情况下取消引用指针,因为不同的数据类型在内存中将具有不同的大小,即 int 为 4 个字节,char 为 1 个字节。

空指针是没有与之关联的数据类型的指针。空指针可以保存任何类型的地址,并且可以被典型地转换为任何类型。 但是,void 指针不能直接取消引用。

int x = 1;
void *p1;
p1 = &x;
cout << *p1 << endl; // this will give error
cout << (int *)(*p) << endl; // this is valid

从根本上说,在 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

这行不通,但 void * 可以在定义指向函数的泛型指针并将其作为参数传递给另一个函数(类似于 Java 中的回调)或将其定义为类似于 oop 的结构方面有很大帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM