Konzept des Void-Zeigers in der C-Programmierung

Lesezeit: 10 Minuten

Benutzeravatar von AGeek
Ein Geek

Ist es möglich, einen void-Zeiger ohne Typumwandlung in der Programmiersprache C zu dereferenzieren?

Gibt es auch eine Möglichkeit, eine Funktion zu verallgemeinern, die einen Zeiger empfangen und in einem void-Zeiger speichern kann, und können wir mit diesem void-Zeiger eine verallgemeinerte Funktion erstellen?

für zB:

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
}

Ich möchte diese Funktion generisch machen, ohne if-else-Anweisungen zu verwenden – ist das möglich?

Auch wenn es gute Internetartikel gibt, die das Konzept eines void-Zeigers erklären, wäre es von Vorteil, wenn Sie die URLs bereitstellen könnten.

Ist auch Zeigerarithmetik mit Void-Zeigern möglich?

  • Für einige mag dies besser lesbar sein, wenn das * an den „Typ“ und nicht an den Namen angehängt wird. Dh das a ist ein Hinweis auf eine Leere (Erinnerungsloch). Daher teilen wir dem Compiler in jeder print-Anweisung mit, welche Art von ‘Loch/Void’ wir erwarten a zu zeigen, und dann erhalten wir diese Art von Wert von diesem Zeiger. (fällt aus der Recherche einiger size_t-Probleme zu LLP32/LP64-Schwierigkeiten;-)

    – Philipp Oakley

    8. August 2021 um 12:18 Uhr

Benutzeravatar von Alex B
Alex B

Ist es möglich, den void-Zeiger ohne Typumwandlung in der Programmiersprache C zu dereferenzieren …

Nein, void zeigt das Fehlen eines Typs an, es ist nichts, was Sie dereferenzieren oder zuweisen können.

Gibt es eine Möglichkeit, eine Funktion zu verallgemeinern, die einen Zeiger empfangen und in einem void-Zeiger speichern kann, und indem wir diesen void-Zeiger verwenden, können wir eine verallgemeinerte Funktion erstellen.

Sie können es nicht einfach portabel dereferenzieren, da es möglicherweise nicht richtig ausgerichtet ist. Dies kann bei einigen Architekturen wie ARM ein Problem sein, bei denen der Zeiger auf einen Datentyp an der Grenze der Größe des Datentyps ausgerichtet werden muss (z. B. muss der Zeiger auf eine 32-Bit-Ganzzahl an der 4-Byte-Grenze ausgerichtet werden, um dereferenziert zu werden).

Zum Beispiel lesen uint16_t aus 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);

Auch Zeigerarithmetik mit Void-Zeigern möglich…

Zeigerarithmetik ist bei Zeigern von nicht möglich void aufgrund fehlender konkreter Werte unter dem Zeiger und damit der Größe.

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

  • Sofern ich mich nicht falsch erinnere, können Sie eine Leere* auf zwei Arten sicher dereferenzieren. Das Umwandeln in char* ist immer akzeptabel, und wenn Sie den ursprünglichen Typ kennen, auf den es zeigt, können Sie in diesen Typ umwandeln. Die void* hat die Typinformationen verloren, sodass sie woanders gespeichert werden müssten.

    – Dan Olson

    29. März 2009 um 10:30 Uhr

  • Ja, Sie können immer dereferenzieren, wenn Sie in einen anderen Typ umwandeln, aber Sie können dasselbe nicht tun, wenn Sie nicht gießen. Kurz gesagt, der Compiler weiß nicht, welche Assembleranweisungen er für mathematische Operationen verwenden soll bis um du wirfst es.

    – Zachary Hamm

    29. März 2009 um 15:12 Uhr

  • Ich denke, GCC behandelt Arithmetik weiter void * Zeiger gleich char *aber es ist kein Standard und Sie sollten sich nicht darauf verlassen.

    – vergänglich

    30. März 2009 um 17:40 Uhr

  • Ich bin mir nicht sicher, ob ich folgen kann. In dem oben aufgeführten Beispiel OP wird garantiert, dass die eingehenden Typen vom Benutzer der Funktion korrekt sind. Wollen Sie sagen, dass, wenn wir etwas haben, wo wir einem Zeiger einen Wert eines bekannten Typs zuweisen, ihn in einen leeren Zeiger umwandeln und ihn dann wieder in den ursprünglichen Zeigertyp umwandeln, dass er nicht mehr ausgerichtet werden könnte? Ich verstehe nicht, warum der Compiler Sie so untergraben würde, dass Sie nur zufällig Dinge ausrichten, nur weil Sie sie in einen void-Zeiger umwandeln. Oder sagen Sie einfach, dass wir dem Benutzer nicht vertrauen können, dass er die Art der Argumente kennt, die er an die Funktion übergeben hat?

    – doliver

    14. November 2014 um 23:28 Uhr


  • @doliver Ich meinte # 2 (“wir können dem Benutzer nicht vertrauen, dass er die Art der Argumente kennt, die er an die Funktion übergeben hat”). Aber wenn ich meine Antwort von vor 6 Jahren noch einmal durchlese (ähm, ist das wirklich so lange her?), kann ich sehen, was du meinst, es ist nicht so stets Der Fall: Wenn der ursprüngliche Zeiger auf den richtigen Typ zeigte, war er bereits ausgerichtet, sodass er ohne Ausrichtungsprobleme sicher gecastet werden konnte.

    – Alex B

    19. April 2015 um 16:37 Uhr

In C, a void * kann ohne explizite Umwandlung in einen Zeiger auf ein Objekt eines anderen Typs umgewandelt werden:

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

Dies hilft jedoch nicht dabei, Ihre Funktion allgemeiner zu schreiben.

Sie können a nicht dereferenzieren void * mit der Konvertierung in einen anderen Zeigertyp, da die Dereferenzierung eines Zeigers den Wert des Objekts erhält, auf das gezeigt wird. Ein nackt void ist kein gültiger Typ, also wird a dereferenziert void * Ist nicht möglich.

Bei der Zeigerarithmetik geht es darum, Zeigerwerte um Vielfache von zu ändern sizeof die Objekte, auf die gezeigt wird. Nochmal, weil void ist kein echter Typ, sizeof(void) hat keine Bedeutung, daher ist Zeigerarithmetik nicht gültig void *. (Einige Implementierungen erlauben dies, indem sie die äquivalente Zeigerarithmetik für verwenden char *.)

  • @CharlesBailey In deinem Code schreibst du void abc(void *a, int b). Aber warum nicht verwenden void abc(int *a, int b)da Sie in Ihrer Funktion schließlich definieren werden int *test = a;, es würde eine Variable sparen, und ich sehe keine anderen Vorteile, wenn ich eine andere Variable definiere. Ich sehe viele Codes, die auf diese Weise geschrieben wurden void * als Parameter und Casting-Variablen später in der Funktion. Aber da diese Funktion vom Autor geschrieben wurde, muss er die Verwendung der Variablen kennen, also warum verwenden void *? Vielen Dank

    – Löwe Lai

    27. Oktober 2017 um 7:01 Uhr


  • Ich glaube, was Sie sagen wollten, ist: “Sie können a nicht dereferenzieren void * ohne Konvertieren in einen anderen Zeigertyp”

    – öter

    17. Februar um 15:40 Uhr

Benutzeravatar von Erich Kitzmüller
Erich Kitzmüller

Sie sollten sich darüber im Klaren sein, dass es in C im Gegensatz zu Java oder C# absolut keine Möglichkeit gibt, den Typ von Objekt a erfolgreich zu “erraten”. void* Zeiger zeigt auf. Etwas ähnliches getClass() einfach nicht existiert, da diese Informationen nirgends zu finden sind. Aus diesem Grund enthält die Art von “Generikum”, nach der Sie suchen, immer explizite Metainformationen, wie z int b in Ihrem Beispiel oder die Formatzeichenfolge in der printf Familie von Funktionen.

Benutzeravatar von Sneha
Sneha

Ein Void-Zeiger wird als generischer Zeiger bezeichnet, der auf Variablen beliebigen Datentyps verweisen kann.

Megharajs Benutzeravatar
Megharaj

Bisher ist meine Untertreibung zum Void-Zeiger wie folgt.

Wenn eine Zeigervariable mit dem Schlüsselwort void deklariert wird, wird sie zu einer Allzweck-Zeigervariable. Einer Void-Pointer-Variablen kann die Adresse einer beliebigen Variablen eines beliebigen Datentyps (char, int, float usw.) zugewiesen werden.

main()
{
    int *p;

    void *vp;

    vp=p;
} 

Da dem void-Zeiger ein anderer Datentyp-Zeiger zugewiesen werden kann, habe ich ihn in der Funktion absolut_value (Code unten gezeigt) verwendet. Um eine allgemeine Funktion zu machen.

Ich habe versucht, einen einfachen C-Code zu schreiben, der Integer oder Float als Argument nimmt und versucht, es +ve zu machen, wenn es negativ ist. Ich habe folgenden Code geschrieben,

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

Aber ich habe einen Fehler bekommen, also habe ich erfahren, dass mein Verständnis mit dem Void-Zeiger nicht korrekt ist :(. Also werde ich jetzt dazu übergehen, Punkte zu sammeln, warum das so ist.

Die Dinge, die ich mehr über Void-Zeiger verstehen muss, sind die.

Wir müssen die Zeigervariable void typisieren, um sie zu dereferenzieren. Dies liegt daran, dass einem void-Zeiger kein Datentyp zugeordnet ist. Der Compiler kann auf keinen Fall wissen (oder erraten?), auf welche Art von Daten der void-Zeiger zeigt. Um also die Daten zu nehmen, auf die ein void-Zeiger zeigt, typisieren wir sie mit dem korrekten Typ der Daten, die sich in der Position des void-Zeigers befinden.

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

}

Ein void-Zeiger kann sehr nützlich sein, wenn der Programmierer sich über den Datentyp der vom Endbenutzer eingegebenen Daten nicht sicher ist. In einem solchen Fall kann der Programmierer einen Void-Zeiger verwenden, um auf die Stelle des unbekannten Datentyps zu zeigen. Das Programm kann so eingestellt werden, dass es den Benutzer auffordert, die Art der Daten mitzuteilen, und die Typumwandlung kann gemäß den vom Benutzer eingegebenen Informationen durchgeführt werden. Ein Code-Snippet ist unten angegeben.

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
}

Ein weiterer wichtiger Punkt, den Sie bei void-Zeigern beachten sollten, ist, dass in einem void-Zeiger keine Zeigerarithmetik durchgeführt werden kann.

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, jetzt habe ich verstanden, was mein Fehler war. Ich korrigiere gleich.

Verweise :

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

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

Der neue Code ist wie unten gezeigt.


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

Vielen Dank,

Benutzeravatar von zvrba
zvrba

Nein, das ist nicht möglich. Welchen Typ soll der dereferenzierte Wert haben?

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

  • Ist dieses Programm möglich… Bitte prüfen Sie, ob dies in C-Programmierung möglich ist…

    – Ein Geek

    30. März 2009 um 3:09 Uhr

  • Ja, das ist möglich (obwohl der Code ohne Bereichsprüfung für b gefährlich ist). Printf akzeptiert eine variable Anzahl von Argumenten und a wird einfach als beliebiger Zeiger (ohne Typinformationen) auf den Stapel geschoben und mithilfe von va_arg-Makros unter Verwendung von Informationen aus der Formatzeichenfolge in die printf-Funktion eingefügt.

    – hlovdal

    15. April 2009 um 15:12 Uhr

  • @SiegeX: Bitte beschreiben Sie, was nicht portabel ist und was möglicherweise undefiniert ist.

    – Gauthier

    31. Oktober 2011 um 9:13 Uhr

  • @Gauthier das Übergeben einer Variablen, die Formatbezeichner enthält, ist nicht portierbar und möglicherweise undefiniertes Verhalten. Wenn Sie so etwas tun möchten, dann schauen Sie sich die ‘vs’-Variante von an printf. Diese Antwort hat ein gutes Beispiel dafür.

    – SiegeX

    1. November 2011 um 17:54 Uhr

  • In der Praxis würde ich wahrscheinlich ersetzen int b mit einer Aufzählung, aber jede spätere Änderung an dieser Aufzählung würde diese Funktion zerstören.

    – Jack Stark

    20. Mai 2014 um 17:26 Uhr

1423540cookie-checkKonzept des Void-Zeigers in der C-Programmierung

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy