简体   繁体   English

C编程中void指针的概念

[英]Concept of void pointer in C programming

Is it possible to dereference a void pointer without type-casting in the C programming language?在 C 编程语言中,是否可以在不进行类型转换的情况下取消引用 void 指针?

Also, is there any way of generalizing a function which can receive a pointer and store it in a void pointer and by using that void pointer, can we make a generalized function?另外,是否有任何方法可以泛化一个可以接收指针并将其存储在空指针中的函数,并且通过使用该空指针,我们可以创建一个泛化函数吗?

for eg:例如:

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
}

I want to make this function generic without using if-else statements - is this possible?我想让这个函数通用而不使用 if-else 语句 - 这可能吗?

Also if there are good internet articles which explain the concept of a void pointer, then it would be beneficial if you could provide the URLs.此外,如果有很好的互联网文章解释了空指针的概念,那么如果您能提供 URL,那将是有益的。

Also, is pointer arithmetic with void pointers possible?另外,是否可以使用空指针进行指针运算?

Is it possible to dereference the void pointer without type-casting in C programming language...是否可以在 C 编程语言中不进行类型转换的情况下取消引用 void 指针...

No, void indicates the absence of type, it is not something you can dereference or assign to.不, void表示没有类型,它不是您可以取消引用或分配的东西。

is there is any way of generalizing a function which can receive pointer and store it in void pointer and by using that void pointer we can make a generalized function..是否有任何方法可以泛化一个可以接收指针并将其存储在 void 指针中的函数,并且通过使用该 void 指针,我们可以创建一个泛化函数..

You cannot just dereference it in a portable way, as it may not be properly aligned.您不能只是以可移植的方式取消引用它,因为它可能没有正确对齐。 It may be an issue on some architectures like ARM, where pointer to a data type must be aligned at boundary of the size of data type (eg pointer to 32-bit integer must be aligned at 4-byte boundary to be dereferenced).这可能是一些架构上的问题,例如 ARM,其中指向数据类型的指针必须在数据类型大小的边界对齐(例如,指向 32 位整数的指针必须在 4 字节边界对齐才能取消引用)。

For example, reading uint16_t from void* :例如,从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);

Also, is pointer arithmetic with void pointers possible...此外,是否可以使用空指针进行指针算术...

Pointer arithmetic is not possible on pointers of void due to lack of concrete value underneath the pointer and hence the size.由于在指针下方缺乏具体值以及大小,因此无法在void指针上进行指针运算。

void* p = ...
void *p2 = p + 1; /* what exactly is the size of void?? */

In C, a void * can be converted to a pointer to an object of a different type without an explicit cast:在 C 中,可以将void *转换为指向不同类型对象的指针,而无需显式转换:

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

This doesn't help with writing your function in a more generic way, though.但是,这无助于以更通用的方式编写函数。

You can't dereference a void * with converting it to a different pointer type as dereferencing a pointer is obtaining the value of the pointed-to object.您不能取消引用void *并将其转换为不同的指针类型,因为取消引用指针是获取指向对象的值。 A naked void is not a valid type so derefencing a void * is not possible.void不是有效类型,因此不可能取消对void *引用。

Pointer arithmetic is about changing pointer values by multiples of the sizeof the pointed-to objects.指针算术是关于将指针值更改为指向对象sizeof的倍数。 Again, because void is not a true type, sizeof(void) has no meaning so pointer arithmetic is not valid on void * .同样,因为void不是真正的类型,所以sizeof(void)没有意义,所以指针算术在void *void * (Some implementations allow it, using the equivalent pointer arithmetic for char * .) (一些实现允许它,使用char *的等效指针算法。)

You should be aware that in C, unlike Java or C#, there is absolutely no possibility to successfully "guess" the type of object a void* pointer points at.您应该知道,在 C 中,与 Java 或 C# 不同,绝对不可能成功“猜测” void*指针指向的对象类型。 Something similar to getClass() simply doesn't exist, since this information is nowhere to be found.getClass()类似的东西根本不存在,因为找不到此信息。 For that reason, the kind of "generic" you are looking for always comes with explicit metainformation, like the int b in your example or the format string in the printf family of functions.出于这个原因,您正在寻找的那种“通用”总是带有显式元信息,例如您的示例中的int bprintf系列函数中的格式字符串。

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

So far my understating on void pointer is as follows.到目前为止,我对 void 指针的理解如下。

When a pointer variable is declared using keyword void – it becomes a general purpose pointer variable.当使用关键字 void 声明指针变量时,它变成了通用指针变量。 Address of any variable of any data type (char, int, float etc.)can be assigned to a void pointer variable.任何数据类型(char、int、float 等)的任何变量的地址都可以分配给 void 指针变量。

main()
{
    int *p;

    void *vp;

    vp=p;
} 

Since other data type pointer can be assigned to void pointer, so I used it in absolut_value(code shown below) function.由于其他数据类型的指针可以分配给void指针,所以我在absolut_value(如下所示的代码)函数中使用了它。 To make a general function.做一个通用的功能。

I tried to write a simple C code which takes integer or float as a an argument and tries to make it +ve, if negative.我试图编写一个简单的 C 代码,它以整数或浮点数作为参数,并尝试使其为 +ve,如果为负数。 I wrote the following code,我写了以下代码,

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

But I was getting error, so I came to know my understanding with void pointer is not correct :(. So now I will move towards to collect points why is that so.但是我遇到了错误,所以我开始知道我对 void 指针的理解是不正确的 :(。所以现在我将转向收集积分,为什么会这样。

The things that i need to understand more on void pointers is that.我需要了解更多关于空指针的事情就是这样。

We need to typecast the void pointer variable to dereference it.我们需要对 void 指针变量进行类型转换以取消引用它。 This is because a void pointer has no data type associated with it.这是因为 void 指针没有与之关联的数据类型。 There is no way the compiler can know (or guess?) what type of data is pointed to by the void pointer.编译器无法知道(或猜测?) void 指针指向什么类型的数据。 So to take the data pointed to by a void pointer we typecast it with the correct type of the data holded inside the void pointers location.因此,为了获取 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) );

}

A void pointer can be really useful if the programmer is not sure about the data type of data inputted by the end user.如果程序员不确定最终用户输入的数据的数据类型,void 指针可能非常有用。 In such a case the programmer can use a void pointer to point to the location of the unknown data type.在这种情况下,程序员可以使用空指针指向未知数据类型的位置。 The program can be set in such a way to ask the user to inform the type of data and type casting can be performed according to the information inputted by the user.程序可以设置为要求用户告知数据类型,并根据用户输入的信息进行类型转换。 A code snippet is given below.下面给出了一个代码片段。

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
}

Another important point you should keep in mind about void pointers is that – pointer arithmetic can not be performed in a void 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.

So now I understood what was my mistake.所以现在我明白我的错误是什么了。 I am correcting the same.我正在纠正同样的问题。

References :参考 :

http://www.antoarts.com/void-pointers-in-c/ http://www.antoarts.com/void-pointers-in-c/

http://www.circuitstoday.com/void-pointers-in-c . http://www.circuitstoday.com/void-pointers-in-c

The New code is as shown below.新代码如下所示。


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

Thank you,谢谢,

No, it is not possible.不,这是不可能的。 What type should the dereferenced value have?解除引用的值应该具有什么类型?

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

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

6.13 — Void pointers 6.13 — 空指针

Because the void pointer does not know what type of object it is pointing to, it cannot be dereferenced directly!因为void指针不知道它指向的是什么类型的对象,所以不能直接解引用! Rather, the void pointer must first be explicitly cast to another pointer type before it is dereferenced.相反,在取消引用之前,必须首先将 void 指针显式转换为另一种指针类型。

If a void pointer doesn't know what it's pointing to, how do we know what to cast it to?如果一个 void 指针不知道它指向什么,我们怎么知道将它转换为什么? Ultimately, that is up to you to keep track of.最终,这取决于您来跟踪。

Void pointer miscellany空指针杂项

It is not possible to do pointer arithmetic on a void pointer.不可能对空指针进行指针运算。 This is because pointer arithmetic requires the pointer to know what size object it is pointing to, so it can increment or decrement the pointer appropriately.这是因为指针运算需要指针知道它指向的对象大小,因此它可以适当地增加或减少指针。

Assuming the machine's memory is byte-addressable and does not require aligned accesses, the most generic and atomic (closest to the machine level representation) way of interpreting a void* is as a pointer-to-a-byte, uint8_t* .假设机器的内存是字节可寻址的并且不需要对齐访问,解释void*的最通用和原子(最接近机器级表示)的方法是作为指向字节的uint8_t* Casting a void* to a uint8_t* would allow you to, for example, print out the first 1/2/4/8/however-many-you-desire bytes starting at that address, but you can't do much else.例如,将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);
}

I want to make this function generic, without using ifs;我想让这个函数通用,不使用 ifs; is it possible?是否有可能?

The only simple way I see is to use overloading .. which is not available in C programming langage AFAIK.我看到的唯一简单方法是使用重载 .. 这在 C 编程语言 AFAIK 中不可用。

Did you consider the C++ programming langage for your programm ?您是否考虑过 C++ 编程语言? Or is there any constraint that forbids its use?或者是否有任何限制禁止其使用?

You can easily print a void printer您可以轻松打印空白打印机

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

Because C is statically-typed, strongly-typed language, you must decide type of variable before compile.由于 C 是静态类型的强类型语言,因此必须在编译之前确定变量的类型。 When you try to emulate generics in C, you'll end up attempt to rewrite C++ again, so it would be better to use C++ instead.当您尝试在 C 中模拟泛型时,您最终将再次尝试重写 C++,因此最好改用 C++。

void pointer is a generic pointer.. Address of any datatype of any variable can be assigned to a void pointer. 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 pointers are pointers that has no data type associated with it.A void pointer can hold address of any type and can be typcasted to any type.空指针是没有与之关联的数据类型的指针。空指针可以保存任何类型的地址,并且可以被典型地转换为任何类型。 But, void pointer cannot be directly be dereferenced.但是,void 指针不能直接取消引用。

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

Fundamentally, in C, "types" are a way to interpret bytes in memory.从根本上说,在 C 中,“类型”是一种解释内存中字节的方法。 For example, what the following code比如下面的代码

struct Point {
  int x;
  int y;
};

int main() {
  struct Point p;
  p.x = 0;
  p.y = 0;
}

Says "When I run main, I want to allocate 4 (size of integer) + 4 (size of integer) = 8 (total bytes) of memory. When I write '.x' as a lvalue on a value with the type label Point at compile time, retrieve data from the pointer's memory location plus four bytes. Give the return value the compile-time label "int.""说“当我运行 main 时,我想分配 4(整数大小)+ 4(整数大小)= 8(总字节数)的内存。当我将 '.x' 作为左值写入具有类型标签的值时指向编译时,从指针的内存位置加上四个字节检索数据。给返回值编译时标签“int”。

Inside the computer at runtime, your "Point" structure looks like this:在运行时在计算机内部,您的“点”结构如下所示:

00000000 00000000 00000000 00000000 00000000 00000000 00000000

And here's what your void* data type might look like: (assuming a 32-bit computer)这就是您的void*数据类型可能的样子:(假设是 32 位计算机)

10001010 11111001 00010010 11000101

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

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

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