C编程中void指针的概念

发布于 2024-07-15 20:32:12 字数 581 浏览 3 评论 0原文

在 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 指针的概念,那么如果您能提供 URL,将会很有帮助。

另外,可以使用 void 指针进行指针算术吗?

Is it possible to dereference a void pointer without type-casting in the C programming language?

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 e.g.:

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?

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.

Also, is pointer arithmetic with void pointers possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

呆° 2024-07-22 20:32:12

在 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 指针进行指针算术。

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

Is it possible to dereference the void pointer without type-casting in C programming language...

No, void indicates the absence of type, it is not something you can dereference or assign to.

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..

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 (e.g. pointer to 32-bit integer must be aligned at 4-byte boundary to be dereferenced).

For example, reading uint16_t from 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);

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* p = ...
void *p2 = p + 1; /* what exactly is the size of void?? */
半世晨晓 2024-07-22 20:32:12

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

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

但这对于以更通用的方式编写函数没有帮助。

您无法通过将 void * 转换为不同的指针类型来取消引用,因为取消引用指针就是获取所指向对象的值。 裸 void 不是有效类型,因此无法取消引用 void *

指针算术是将指针值更改为所指向对象的大小的倍数。 同样,由于 void 不是真正的类型,因此 sizeof(void) 没有任何意义,因此指针算术在 void * 上无效。 (某些实现允许这样做,使用 char * 的等效指针算术。)

In C, a void * can be converted to a pointer to an object of a different type without an explicit cast:

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. A naked void is not a valid type so derefencing a void * is not possible.

Pointer arithmetic is about changing pointer values by multiples of the sizeof the pointed-to objects. Again, because void is not a true type, sizeof(void) has no meaning so pointer arithmetic is not valid on void *. (Some implementations allow it, using the equivalent pointer arithmetic for char *.)

玩世 2024-07-22 20:32:12

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

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. Something similar to getClass() simply doesn't exist, since this information is nowhere to be found. 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.

暗藏城府 2024-07-22 20:32:12

void 指针称为通用指针,它可以引用任何数据类型的变量。

A void pointer is known as generic pointer, which can refer to variables of any data type.

梦里寻她 2024-07-22 20:32:12

到目前为止,我对 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 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;
}   

谢谢你,

So far my understating on void pointer is as follows.

When a pointer variable is declared using keyword void – it becomes a general purpose pointer variable. Address of any variable of any data type (char, int, float etc.)can be assigned to a void pointer variable.

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. 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. 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.

The things that i need to understand more on void pointers is that.

We need to typecast the void pointer variable to dereference it. This is because a void pointer has no data type associated with it. There is no way the compiler can know (or guess?) what type of data is pointed to by the void pointer. 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 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. 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 *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.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,

两个我 2024-07-22 20:32:12

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

No, it is not possible. What type should the dereferenced value have?

梦初启 2024-07-22 20:32:12
void abc(void *a, int b) {
  char *format[] = {"%d", "%c", "%f"};
  printf(format[b-1], a);
}
void abc(void *a, int b) {
  char *format[] = {"%d", "%c", "%f"};
  printf(format[b-1], a);
}
木森分化 2024-07-22 20:32:12

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

6.13 — 空指针

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

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

空指针杂项

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

假设机器的内存是字节可寻址的并且不需要对齐访问,则解释 void* 的最通用和原子(最接近机器级表示)的方式是作为指向 a- 的指针字节,uint8_t*。 例如,将 void* 转换为 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);
}

Here is a brief pointer on void pointers: https://www.learncpp.com/cpp-tutorial/613-void-pointers/

6.13 — Void pointers

Because the void pointer does not know what type of object it is pointing to, it cannot be dereferenced directly! Rather, the void pointer must first be explicitly cast to another pointer type before it is dereferenced.

If a void pointer doesn't know what it's pointing to, how do we know what to cast it to? 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*. 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.

uint8_t* byte_p = (uint8_t*)p;
for (uint8_t* i = byte_p; i < byte_p + 8; i++) {
  printf("%x ",*i);
}
生生漫 2024-07-22 20:32:12

我想让这个函数变得通用,
不使用 if; 这可能吗?

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

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

I want to make this function generic,
without using ifs; is it possible?

The only simple way I see is to use overloading .. which is not available in C programming langage AFAIK.

Did you consider the C++ programming langage for your programm ? Or is there any constraint that forbids its use?

童话里做英雄 2024-07-22 20:32:12

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

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

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.

int x = 1;
void *p1;
p1 = &x;
cout << *p1 << endl; // this will give error
cout << (int *)(*p) << endl; // this is valid
潜移默化 2024-07-22 20:32:12

可以轻松打印虚空打印机

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

You can easily print a void printer

int p=15;
void *q;
q=&p;
printf("%d",*((int*)q));
谷夏 2024-07-22 20:32:12

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

Because C is statically-typed, strongly-typed language, you must decide type of variable before compile. 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.

带刺的爱情 2024-07-22 20:32:12

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

void pointer is a generic pointer.. Address of any datatype of any variable can be assigned to a void pointer.

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
空城缀染半城烟沙 2024-07-22 20:32:12

如果不指定指针类型,则无法取消引用指针,因为不同的数据类型在内存中具有不同的大小,即 int 为 4 个字节,char 为 1 个字节。

You cannot dereference a pointer without specifying its type because different data types will have different sizes in memory i.e. an int being 4 bytes, a char being 1 byte.

从根本上来说,在 C 语言中,“类型”是解释内存中字节的一种方式。 例如,以下代码

struct Point {
  int x;
  int y;
};

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

表示“当我运行 main 时,我想分配 4(整数大小)+ 4(整数大小)= 8(总字节)内存。当我将 '.x' 写为左值时在编译时带有类型标签 Point 的值上,从指针的内存位置检索数据加上四个字节,为返回值提供编译时标签“int”。

在运行时的计算机内部,“Point”结构看起来像这样。这:

00000000 00000000 00000000 00000000 00000000 00000000 00000000

您的 void* 数据类型可能如下所示:(假设是 32 位计算机)

10001010 11111001 00010010 11000101

Fundamentally, in C, "types" are a way to interpret bytes in memory. 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.""

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)

10001010 11111001 00010010 11000101
黑寡妇 2024-07-22 20:32:12

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

This won't work, yet void * can help a lot in defining generic pointer to functions and passing it as an argument to another function (similar to callback in Java) or define it a structure similar to oop.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文