132

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ポインタを使用したポインタ演算は可能ですか?

4

16 に答える 16

98

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ポインタの下の具体的な値が不足しているため、ポインタのサイズが不足しているため、ポインタの演算はできません。

void* p = ...
void *p2 = p + 1; /* what exactly is the size of void?? */
于 2009-03-28T10:36:15.110 に答える
32

Cでは、void *明示的なキャストなしで、aを別のタイプのオブジェクトへのポインターに変換できます。

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

ただし、これは、より一般的な方法で関数を作成するのに役立ちません。

void *ポインタを逆参照すると、ポイントされたオブジェクトの値が取得されるため、別のポインタ型に変換して逆参照することはできません。ネイキッドvoidは有効なタイプではないため、aの参照を解除することvoid *はできません。

sizeofポインタ演算とは、ポインタを指すオブジェクトの倍数でポインタ値を変更することです。繰り返しにvoidなりますが、はTrue Typeでsizeof(void)はないため、意味がないため、ポインタ演算はで無効ですvoid *。(一部の実装では、同等のポインター演算を使用して、これを許可していますchar *。)

于 2009-03-28T10:42:38.760 に答える
16

void*C では、Java や C# とは異なり、ポインターが指すオブジェクトの型を正しく「推測」する可能性はまったくないことに注意してください。この情報はどこにも見つからないため、似たようなものはgetClass()単に存在しません。そのため、探している「ジェネリック」の種類には、例や関数ファミリーのint bフォーマット文字列のように、常に明示的なメタ情報が付属しています。printf

于 2009-06-04T07:43:13.440 に答える
7

void ポインターはジェネリック ポインターと呼ばれ、任意のデータ型の変数を参照できます。

于 2010-10-22T15:25:27.643 に答える
7

これまでのところ、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 ポインター変数を型キャストする必要があります。これは、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 ポインターについて留意すべきもう 1 つの重要な点は、ポインター演算は 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;
}   

ありがとうございました、

于 2013-09-19T09:02:35.173 に答える
2
void abc(void *a, int b) {
  char *format[] = {"%d", "%c", "%f"};
  printf(format[b-1], a);
}
于 2009-03-30T00:35:24.630 に答える
2

いいえ、できません。逆参照された値にはどのタイプが必要ですか?

于 2009-03-28T10:37:08.697 に答える
0

ボイドプリンターを簡単に印刷できます

int p=15;
void *q;
q=&p;
printf("%d",*((int*)q));
于 2013-02-15T07:31:16.277 に答える