IT박스

C 프로그래밍에서 void 포인터의 개념

itboxs 2020. 7. 5. 08:15
반응형

C 프로그래밍에서 void 포인터의 개념


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 포인터를 사용한 포인터 산술이 가능합니까?


C 프로그래밍 언어에서 타입 캐스팅을하지 않고 void 포인터를 역 참조 할 수 있습니까?

아니요, void유형이 없음을 나타내며 역 참조하거나 할당 할 수있는 것이 아닙니다.

포인터를 받아서 void 포인터에 저장할 수있는 함수를 일반화하는 방법이 있습니까? 그리고 그 void 포인터를 사용하여 일반화 된 함수를 만들 수 있습니다.

제대로 정렬되지 않았기 때문에 이식 가능한 방식으로 역 참조 할 수는 없습니다. 데이터 유형에 대한 포인터는 데이터 유형 크기의 경계에 정렬되어야하는 ARM과 같은 일부 아키텍처에서는 문제가 될 수 있습니다 (예 : 32 비트 정수에 대한 포인터는 역 참조하려면 4 바이트 경계에 정렬되어야 함).

예를 들어, 읽기 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* p = ...
void *p2 = p + 1; /* what exactly is the size of void?? */

C에서 a void *는 명시 적 캐스트없이 다른 유형의 객체에 대한 포인터로 변환 될 수 있습니다.

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

그래도 더 일반적인 방식으로 함수를 작성하는 데 도움이되지 않습니다.

void *포인터를 역 참조하면 지정된 객체의 값을 가져 오기 때문에 a를 다른 포인터 유형으로 변환하여 a 역 참조 할 수 없습니다 . 나체 void는 유효한 유형이 아니므로 a void *를 역 참조 할 수 없습니다.

포인터 산술은 sizeof지정된 객체의 배수로 포인터 값을 변경하는 것 입니다. 다시 말하지만, void진정한 유형이 아니기 때문에 sizeof(void)의미가 없으므로 포인터 산술이에서 유효하지 않습니다 void *. (일부 구현에서는에 해당하는 포인터 산술을 사용하여 허용합니다 char *.)


C에서는 Java 나 C #과 달리 void * 포인터가 가리키는 객체의 유형을 성공적으로 "추측"할 가능성이 전혀 없습니다. 이 정보를 찾을 수 없기 때문에 "getClass ()"와 비슷한 것이 존재하지 않습니다. 이러한 이유로, 당신이 찾고있는 "일반"의 종류는 항상 예제의 "int b"또는 printf 함수 계열의 형식 문자열과 같은 명시적인 메타 정보와 함께 제공됩니다.


void 포인터는 일반 포인터로 알려져 있으며 모든 데이터 유형의 변수를 나타낼 수 있습니다.


지금까지 void 포인터에 대한 내 주장은 다음과 같습니다.

키워드 void를 사용하여 포인터 변수를 선언하면 범용 포인터 변수가됩니다. 모든 데이터 유형의 변수 (char, int, float 등)의 주소는 void 포인터 변수에 할당 될 수 있습니다.

main()
{
    int *p;

    void *vp;

    vp=p;
} 

다른 데이터 유형 포인터는 void 포인터에 할당 될 수 있으므로 absolut_value (아래 표시된 코드) 함수에서 사용했습니다. 일반적인 기능을 수행합니다.

정수 또는 부동 소수점을 인수로 사용하고 음수이면 + ve로 만드는 간단한 C 코드를 작성하려고했습니다. 다음 코드를 작성했습니다.

#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 포인터에 대해 더 많이 이해해야하는 것은 그 것입니다.

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,


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

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?


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


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

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

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.


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

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.

참고URL : https://stackoverflow.com/questions/692564/concept-of-void-pointer-in-c-programming

반응형