Frage

Ich habe versucht, eine Pseudo -Superstruktur zu erstellen, um eine Array von Strukturen zu drucken. Meine grundlegenden Strukturen sind wie folgt.

/* Type 10 Count */
typedef struct _T10CNT
{
    int _cnt[20];
} T10CNT;

...

/* Type 20 Count */
typedef struct _T20CNT
{
    long _cnt[20];
} T20CNT;
...

Ich habe die folgende Struktur erstellt, um das Array der oben genannten Strukturen zu drucken. Ich habe den Fehler beim Kompilieren des folgenden Code -Snippets von Derferencing -void Zeiger.

typedef struct _CMNCNT
{
    long  _cnt[3];
} CMNCNT;

static int printCommonStatistics(void *cmncntin, int cmncnt_nelem, int cmncnt_elmsize)
{
    int ii;
    for(ii=0; ii<cmncnt_nelem; ii++)
    {
        CMNCNT *cmncnt = (CMNCNT *)&cmncntin[ii*cmncnt_elmsize];
        fprintf(stout,"STATISTICS_INP: %d\n",cmncnt->_cnt[0]);
        fprintf(stout,"STATISTICS_OUT: %d\n",cmncnt->_cnt[1]); 
        fprintf(stout,"STATISTICS_ERR: %d\n",cmncnt->_cnt[2]);
    }
    return SUCCESS;
}

T10CNT struct_array[10];
...
printCommonStatistics(struct_array, NELEM(struct_array), sizeof(struct_array[0]);
...

Meine Absicht ist es, eine gemeinsame Funktion zu haben, um alle Arrays zu drucken. Bitte teilen Sie mir die richtige Art und Weise mit, es zu verwenden.

Schätzen Sie die Hilfe im Voraus.

Bearbeiten: Der Parametername wird von cmncnt in cmncntin geändert. Entschuldigung, es war Tippfehler.

Danke, Mathew liju

War es hilfreich?

Lösung

Ich denke, Ihr Design wird scheitern, aber ich bin auch nicht überzeugt, dass die anderen Antworten, die ich sehe, mit den tieferen Gründen zu tun haben.

Es scheint, dass Sie versuchen, C zu verwenden, um mit generischen Typen umzugehen, etwas, das immer haarig wird. Sie können es tun, wenn Sie vorsichtig sind, aber es ist nicht einfach, und in diesem Fall bezweifle ich, dass es sich lohnen würde.

Tiefere Grund: Nehmen wir an, wir überwinden die bloßen syntaktischen (oder kaum mehr als syntaktischen) Probleme. Ihr Code zeigt, dass T10CNT 20 enthält int und T20CNT enthält 20 long. Auf modernen 64 -Bit -Maschinen - außer unter Win64 - sizeof(long) != sizeof(int). Daher sollte der Code in Ihrer Druckfunktion zwischen Derferenzung unterscheiden int Arrays und long Arrays. In C ++ gibt es eine Regel, dass Sie nicht versuchen sollten, Arrays polymorph zu behandeln, und so etwas ist der Grund. Der CMNCNT -Typ enthält 3 long Werte; Unterscheidet sowohl von den T10CNT- als auch von T20CNT -Strukturen in der Anzahl, obwohl der Basistyp des Array mit T20CNT übereinstimmt.

Stilempfehlung: Ich empfehle dringend, führende Unterstriche für Namen zu vermeiden. Im Allgemeinen sind Namen, die mit Unterstrich beginnen, für die Verwendung der Implementierung reserviert und als Makros verwendet. Makros haben keinen Respekt vor dem Umfang; Wenn die Implementierung ein Makro _CNT definiert, würde sie Ihren Code zerstören. Es gibt Nuancen, welche Namen reserviert sind; Ich werde nicht in diese Nuancen eingehen. Es ist viel einfacher zu denken, dass "Namen, die mit Unterstrichen beginnen, reserviert sind", und es wird Sie von Ärger ablenken.

Stilvorschlag: Ihre Druckfunktion gibt den Erfolg bedingungslos zurück. Das ist nicht sinnvoll; Ihre Funktion sollte nichts zurückgeben, damit der Anrufer nicht auf Erfolg oder Misserfolg testen muss (da er niemals scheitern kann). Ein sorgfältiger Codierer, der feststellt, dass die Funktion einen Status zurückgibt, testet immer den Rückgabestatus und hat einen Fehlerbehandlungscode. Dieser Code wird niemals ausgeführt, also ist er tot, aber es ist schwierig für jeden (oder den Compiler), dies zu bestimmen.

Oberflächenfix: Vorübergehend können wir davon ausgehen, dass Sie behandeln können int und long als Synonyme; Aber Sie müssen aus der Gewohnheit herauskommen zu denken, dass sie Synonyme sind. Das void * Argument ist der richtige Weg zu sagen: "Diese Funktion nimmt einen Zeiger unbestimmter Typ". Innerhalb der Funktion müssen Sie jedoch von a konvertieren void * zu einem bestimmten Typ, bevor Sie die Indizierung durchführen.

typedef struct _CMNCNT
{
    long    count[3];
} CMNCNT;

static void printCommonStatistics(const void *data, size_t nelem, size_t elemsize)
{
    int i;
    for (i = 0; i < nelem; i++)
    {
        const CMNCNT *cmncnt = (const CMNCNT *)((const char *)data + (i * elemsize));
        fprintf(stdout,"STATISTICS_INP: %ld\n", cmncnt->count[0]);
        fprintf(stdout,"STATISTICS_OUT: %ld\n", cmncnt->count[1]); 
        fprintf(stdout,"STATISTICS_ERR: %ld\n", cmncnt->count[2]);
    }
}

(Ich mag die Idee eines Dateistroms aufgerufen stout zu. Anregung: Verwenden Sie Cut'n'Paste für den echten Quellcode-es ist sicherer! Ich benutze im Allgemeinen "sed 's/^/ /' file.c"Um Code für Cut'n'Paste in eine SO -Antwort vorzubereiten.)

Was macht diese Gusslinie? Ich bin froh, dass du gefragt hast ...

  • Der erste Vorgang besteht darin, die zu konvertieren const void * in ein const char *; Auf diese Weise können Sie Byte-Größe-Operationen unter der Adresse durchführen. In den Tagen vor Standard C, char * wurde anstelle von anstelle von verwendet void * als universeller Adressierungsmechanismus.
  • Die nächste Operation fügt die korrekte Anzahl von Bytes hinzu, um den Beginn des iDas Element des Arrays von Objekten der Größe elemsize.
  • Die zweite Besetzung sagt dann dem Compiler "Vertrauen Sie mir - ich weiß, was ich tue" und "behandeln Sie diese Adresse als Adresse einer CMNCNT -Struktur".

Von dort aus ist der Code einfach genug. Beachten Sie, dass da die CMNCNT -Struktur enthält long Wert, ich habe verwendet %ld die Wahrheit zu sagen fprintf().

Da Sie die Daten in dieser Funktion nicht ändern, ist es keine schlechte Idee, die zu verwenden const Qualifikation wie ich.

Beachten Sie, dass wenn Sie treu bleiben sizeof(long) != sizeof(int), Dann benötigen Sie zwei separate Codeblöcke (ich würde separate Funktionen vorschlagen), um sich mit dem Array von zu befassen int'und' Array von long'Strukturtypen.

Andere Tipps

Die Art der Leere wird absichtlich unvollständig gelassen. Daraus folgt, dass Sie keine Leere Zeiger haben, und Sie können auch die Größe davon nehmen. Dies bedeutet, dass Sie den Indexbetreiber nicht wie ein Array verwenden können.

In dem Moment, in dem Sie einem leeren Zeiger etwas zuweisen, gehen alle Typinformationen des ursprünglichen Typs verloren gegangen. Sie können also nur Dereference, wenn Sie es zum ersten Mal auf den ursprünglichen Zeigertyp werfen.

Erstens und das Wichtigste, Sie bestehen T10CNT* zur Funktion, aber Sie versuchen, das zu typern (und dereference) zu typern CMNCNT* in Ihrer Funktion. Dies ist kein gültiges und undefiniertes Verhalten.

Für jede Art von Array -Elementen benötigen Sie eine Funktion Printcommonstatistics. Also, haben Sie eineprintCommonStatisticsInt, printCommonStatisticsLong, printCommonStatisticsChar die alles unterscheiden sich durch ihr erstes Argument (eine nimmt int*, die andere nehmen long*, usw). Sie können sie mit Makros erstellen, um redundanten Code zu vermeiden.

Das Bestehen der Struktur selbst ist keine gute Idee. Seitdem müssen Sie eine neue Funktion für jede unterschiedliche Größe des enthaltenen Arrays innerhalb der Struktur definieren (da es sich um alle unterschiedlichen Typen handelt). Also besser das enthaltene Array direkt bestehen (struct_array[0]._cnt, Rufen Sie die Funktion für jeden Index auf)

Ändern Sie die Funktionserklärung in char * Like SO:

static int printCommonStatistics(char *cmncnt, int cmncnt_nelem, int cmncnt_elmsize)

Der Hohlraumtyp nimmt keine bestimmte Größe an, während ein Zeichen eine Bytegröße übernimmt.

Sie können das nicht tun:

cmncnt->_cnt[0]

Wenn CMNCT ein Leerzeiger ist.

Sie müssen den Typ angeben. Möglicherweise müssen Sie Ihre Implementierung überdenken.

Die Funktion

static int printCommonStatistics(void *cmncntin, int cmncnt_nelem, int cmncnt_elmsize)
{
    char *cmncntinBytes;
    int ii;

    cmncntinBytes = (char *) cmncntin;
    for(ii=0; ii<cmncnt_nelem; ii++)
    {
        CMNCNT *cmncnt = (CMNCNT *)(cmncntinBytes + ii*cmncnt_elmsize);  /* Ptr Line */
        fprintf(stdout,"STATISTICS_INP: %d\n",cmncnt->_cnt[0]);
        fprintf(stdout,"STATISTICS_OUT: %d\n",cmncnt->_cnt[1]); 
        fprintf(stdout,"STATISTICS_ERR: %d\n",cmncnt->_cnt[2]);
    }
    return SUCCESS;
}

Funktioniert bei mir.

Das Problem ist, dass der Code in der Zeile "PTR -Zeile" kommentiert hat. Da unser Zeiger ein Zeichen ist *, bewegen wir uns in der Speichergröße (char) * ii * cmncnt_elemsize vor, was wir wollen, da ein Zeichen ein Byte ist. Ihr Code hat versucht, eine äquivalente Sache zu machen, die sich vorwärts (void) * ii * cmncnt_elemsize vorwärts bewegte, aber void hat keine Größe, sodass der Compiler Ihnen den Fehler gegeben hat.

Ich würde T10CNT und T20CNT ändern, um sowohl int als auch lang anstelle von jeweils zu verwenden. Sie sind abhängig von der Größe (int) == sizeof (lang)

Auf dieser Zeile:

CMNCNT *cmncnt = (CMNCNT *)&cmncnt[ii*cmncnt_elmsize];

Sie versuchen, eine neue Variable namens CMNCNT zu deklarieren, aber eine Variable mit diesem Namen gibt es bereits als Parameter für die Funktion. Möglicherweise möchten Sie einen anderen Variablennamen verwenden, um dies zu lösen.

Möglicherweise möchten Sie auch einen Zeiger an einen CMNCNT an die Funktion anstelle eines voiden Zeigers weitergeben, da der Compiler dann die Zeiger -Arithmetik für Sie ausführt und Sie ihn nicht werfen müssen. Ich sehe nicht den Sinn, einen voiden Zeiger zu übergeben, wenn Sie ihn nur mit ihm an einen CMNCNT übertragen haben. (Dies ist übrigens kein sehr beschreibender Name für einen Datentyp.)

Dein Ausdruck

(CMNCNT *)&cmncntin[ii*cmncnt_elmsize]

Versucht, die Adresse von cmncntin [ii * *cmncnt_elmsize] zu übernehmen und dann diesen Zeiger auf einen Typ zu werfen (cmncnt *). Es kann nicht die Adresse von cmncntin [ii*cmncnt_elmsize] erhalten, da Cmncntin Typ void*hat.

Prise des Studiums C und fügen Sie bei Bedarf Klammern ein.

Informationspunkt: Interne Polsterung kann dies wirklich vermasseln.

Betrachten Sie Struct {char c [6]; }; - Es hat sizeof () = 6. Aber wenn Sie eine Reihe von diesen hätten, könnte jedes Element eine 8 -Byte -Ausrichtung ausgetauscht werden!

Bestimmte Montagevorgänge verarbeiten keine falsch ausgerichteten Daten anmutig. (Wenn ein int beispielsweise zwei Speicherwörter umfasst.) (Ja, ich wurde schon einmal von diesem gebissen.)

.

Zweitens: In der Vergangenheit habe ich variabel große Arrays verwendet. (Ich war damals dumm ...) Es funktioniert, wenn Sie den Typ nicht ändern. (Oder wenn Sie eine Vereinigung der Typen haben.)

Z.B:

struct T { int sizeOfArray;  int data[1]; };

Zugewiesen wie

T * t = (T *) malloc( sizeof(T) + sizeof(int)*(NUMBER-1) );
                      t->sizeOfArray = NUMBER;

(Obwohl Polsterung/Ausrichtung Sie immer noch vermasseln kann.)

.

Dritten: Überlegen Sie:

   struct T {
     int sizeOfArray;
     enum FOO arrayType;
     union U { short s; int i; long l; float f; double d; } data [1];
    };

Es löst Probleme mit dem Wissen, wie man die Daten ausdruckt.

.

Viertens: Sie könnten einfach das int/lange Array an Ihre Funktion und nicht in die Struktur übergeben. Z.B:

void printCommonStatistics( int * data, int count )
{
  for( int i=0;  i<count;  i++ )
    cout << "FOO: " << data[i] << endl;
}

Aufgerufen über:

_T10CNT  foo;
printCommonStatistics( foo._cnt, 20 );

Oder:

 int a[10], b[20], c[30];
printCommonStatistics( a, 10 );
printCommonStatistics( b, 20 );
printCommonStatistics( c, 30 );

Dies funktioniert viel besser, als Daten in Strukturen zu verbergen. Wenn Sie Mitglieder zu einem Ihrer Strukturen hinzufügen, kann sich das Layout zwischen Ihren Strukturen ändern und nicht mehr konsistent sein. (Bedeutet, dass die Adresse von _cnt relativ zum Start der Struktur sich für _t10cnt und nicht für _t20cnt ändern kann. Fun Debugging -Zeiten dort. Eine einzelne Struktur mit einer gewerkschaftlichen Nutzlast würde dies vermeiden.)

Z.B:

struct FOO {
  union {
         int     bar  [10];
          long biff [20];
   } u;
}

.

Fünftens: Wenn Sie Strukturen verwenden müssen ... C ++, iostreams und Templating wären viel sauberer zu implementieren.

Z.B:

template<class TYPE> void printCommonStatistics( TYPE & mystruct, int count )
{
  for( int i=0;  i<count;  i++ )
    cout << "FOO: " << mystruct._cnt[i] << endl;
}      /* Assumes all mystruct's have a "_cnt" member. */

Aber das ist wahrscheinlich nicht das, wonach Sie suchen ...

C ist nicht meine Tasse O'Java, aber ich denke, Ihr Problem ist, dass "void *cmncnt" cmncnt *cmncnt sein sollte.

Fühlen Sie sich jetzt frei, mich zu korrigieren, C -Programmierer, und sagen Sie mir, dass Java -Programmierer nicht schöne Dinge haben können.

This line is kind of tortured, don'tcha think?

CMNCNT *cmncnt = (CMNCNT *)&cmncntin[ii*cmncnt_elmsize];

How about something more like

CMNCNT *cmncnt = ((CMNCNT *)(cmncntin + (ii * cmncnt_elmsize));

Or better yet, if cmncnt_elmsize = sizeof(CMNCNT)

CMNCNT *cmncnt = ((CMNCNT *)cmncntin) + ii;

That should also get rid of the warning, since you are no longer dereferencing a void *.

BTW: I'm not real sure why you are doing it this way, but if cmncnt_elmsize is sometimes not sizeof(CMNCNT), and can in fact vary from call to call, I'd suggest rethinking this design. I suppose there could be a good reason for it, but it looks really shaky to me. I can almost guarantee there is a better way to design things.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top