Adresse, Datentyp und Name einer Variablen zur Laufzeit bestimmen



  • Hallo,

    in einer Header-Datei lege ich Pointer-Variablen unterschiedlichen Datentyps an z.B.
    short int* pSV1;
    Ich habe eine CListCtrl mit den Spalten "Adresse", "Datentyp" und "Name". Jetzt sollen zur Laufzeit diese Informationen in die Liste eingetragen werden.

    Aber wie komme ich an den Namen der Variablen bzw. die Adresse welche der Debugger wohl selbst festlegt. Falls mir jemand eine Lösung oder einen Ansatz für das Problem hat wäre ich sehr dankbar.

    MfG

    jay



  • Zur Laufzeit sind dem Programm die Variablennamen nicht mehr bekannt. Die Speicheradresse kannste ja durch eine Referenz aufrufen lassen. Und Datentyp, hum, müssteste dann jedesmal prüfen. Zum Beispiel ob Zeichen enthalten sind oder sowas...



  • cappasa schrieb:

    Aber wie komme ich an den Namen der Variablen bzw. die Adresse welche der Debugger wohl selbst festlegt. Falls mir jemand eine Lösung oder einen Ansatz für das Problem hat wäre ich sehr dankbar.

    An die Adresse kommst du über den Adressoperator &. An die Variablennamen kommst du zur Laufzeit nicht. Für die Namen und Typen richtest du dir am besten zur Compilezeit etwas ein. Zum Beispiel könntest du mit überladenen Funktionen arbeiten:

    std::string GetType(int)
    {
        return "int";
    }
    
    std::string GetType(double)
    {
        return "double";
    }
    

    Templates wären auch etwas, aber ich weiss nicht, ob du die kennst. Für Variablennamen kannst du dir ein Makro schreiben:

    #define VARNAME(VAR) #VAR
    

    Es ist allerdings fraglich, ob sich das so in einer Tabelle zusammenfassen lässt. Wie speicherst du überhaupt unterschiedliche Datentypen?

    Du willst damit bestimmt etwas ausprobieren. Aber C++ ist für dein Vorhaben aufgrund der statischen Typisierung nicht besonders geeignet. Zur Laufzeit existieren kaum Informationen über Typen und Variablen. Ich habe dir nun einen Weg gezeigt, mit dem du sowas zur Compilezeit teilweise erreichen kannst. Aber besonders sinnvoll ist das wie gesagt nicht. Solange es jedoch nur ums Ausprobieren geht, macht das ja nichts... 🙂

    Kóyaánasqatsi schrieb:

    Und Datentyp, hum, müssteste dann jedesmal prüfen. Zum Beispiel ob Zeichen enthalten sind oder sowas...

    Den Datentyp kannst du ohne RTTI zur Laufzeit nicht sinnvoll prüfen. Du weisst ja nicht, wie die Bitmuster zu interpretieren sind (und was somit ein Zeichen ist).



  • Kóyaánasqatsi schrieb:

    Zur Laufzeit sind dem Programm die Variablennamen nicht mehr bekannt. Die Speicheradresse kannste ja durch eine Referenz aufrufen lassen. Und Datentyp, hum, müssteste dann jedesmal prüfen. Zum Beispiel ob Zeichen enthalten sind oder sowas...

    Zeig mal ein Beispiel bitte.



  • hustbaer schrieb:

    Kóyaánasqatsi schrieb:

    Zur Laufzeit sind dem Programm die Variablennamen nicht mehr bekannt. Die Speicheradresse kannste ja durch eine Referenz aufrufen lassen. Und Datentyp, hum, müssteste dann jedesmal prüfen. Zum Beispiel ob Zeichen enthalten sind oder sowas...

    Zeig mal ein Beispiel bitte.

    bool IsChar( char *pointer, unsigned short bufferLength )
    {
    	for( unsigned short i = 0; i < bufferLength; ++i )
    	{
    		///// It's a ASCII chain /////
    		if( ( pointer[i] < 0x7F && pointer[i] > 0x8 ) && ( pointer[i + 1] < 0x7F && pointer[i + 1] > 0x8 ) )
    			return true;
    		else
    			return false;
    	}
    };
    

    (UNGETESTET!)
    Und wenn man schonmal weiss, das eine ASCII-Kette besteht, dann kann man wohl eher sagen, dass es sich dabei um einen char handelt. Außerdem geht mir dein Verhalten auf die Nüsse... 👎



  • Kóyaánasqatsi schrieb:

    Und wenn man schonmal weiss, das eine ASCII-Kette besteht, dann kann man wohl eher sagen, dass es sich dabei um einen char handelt.

    😕

    int value = 0x09204913;
    IsChar(&value, sizeof(value));
    

    Heuristik will gelernt sein.
    Dein Code verhält sich außerdem undefiniert, funktioniert also auf mehreren Ebenen nicht.



  • Kóyaánasqatsi schrieb:

    Außerdem geht mir dein Verhalten auf die Nüsse... 👎

    Das mag zwar sein udn ruht vermutlich auf Gegenseitigkeit. Trotzdem solltet ihr sowas privat klären und nicht hier im Forum.



  • @pumuckl
    Ok.

    Jau, den Code habe ich heute morgen schnell dahin geschmiert um zu hustbaer zu zeigen, was ich meine. So oder so wird es nahezu unmöglich, den genauen Datentypen zu ermitteln. Es sei denn, du legst sowas vorm kompilieren fest, dass würde mich dann auch interessieren 🙂 .



  • Kóyaánasqatsi schrieb:

    Es sei denn, du legst sowas vorm kompilieren fest, dass würde mich dann auch interessieren 🙂 .

    Steht zum Beispiel in meinem oberen Post. 😉

    Aber wie gesagt, besonders schön und sinnvoll ist das nicht.



  • danke erstmal für eure Antworten. Natürlich kann man die Adresse mittels dem Referenzoperator herausbekommen. Was passiert allerdings wenn ich damit Speicher allokiere, wo finde ich dann die Startadresse des zu belegenden Signalvektors? Mit &pSV1 &pSV2 usw. erhalte ich Adressen 1241464 1241468 im Abstand von 4 Bits / Bytes? Das sind ja nur die Adressen der Pointer, ich such allerdings den Anfang des zu belegenden Speichers den ich wie folgt allokiere...

    pSV1 = (short int*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 2 * sizeof(short int) * GlPar.nNperB);
    

    Die Datentypen sind im voraus bekannt! Ich lege sie ja in einer Header-Datei an:
    short int* pSV1;
    int* pSV2;
    long int* pSV3;
    float* pSV4;
    double* pSV5;

    Der Vorschlag von Nexus gefällt mir somit mal ganz gut. Das Stichwort heisst denke ich Funktion-Templates. Darüber lässt sich zumindest mit dem korrekten Datentyp arbeiten.

    Ich will mich jetzt mal, in Bezug auf den Namen der Variablen zur Laufzeit, vorsichtig äussern: ein Freund meinte das er im "Linker-Output (Map)" zu finden sein könnte. Kennt sich vielleicht damit jemand aus und weiß wie man da ran kommt?



  • cappasa schrieb:

    danke erstmal für eure Antworten. Natürlich kann man die Adresse mittels dem Referenzoperator herausbekommen. Was passiert allerdings wenn ich damit Speicher allokiere, wo finde ich dann die Startadresse des zu belegenden Signalvektors? Mit &pSV1 &pSV2 usw. erhalte ich Adressen 1241464 1241468 im Abstand von 4 Bits / Bytes? Das sind ja nur die Adressen der Pointer, ich such allerdings den Anfang des zu belegenden Speichers den ich wie folgt allokiere...

    pSV1 = (short int*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 2 * sizeof(short int) * GlPar.nNperB);
    

    Hm. Blöde Frage, aber ist dir bewusst, was Pointer sind? pSV1 ist ein Pointer, der Wert des Pointers ist eine Speicheradresse. HeapAlloc dürfte die Adresse des allokierten Speichers zurückgeben, (sonst könntest du ihn ja nie wiederfinden und benutzen), und die Zuweisung speichert diese Adresse in pSV1. Und deine Frage war jetzt, welche Anfangsadresse der Speicher hat, den du allokiert hast?



  • cappasa schrieb:

    Ich will mich jetzt mal, in Bezug auf den Namen der Variablen zur Laufzeit, vorsichtig äussern: ein Freund meinte das er im "Linker-Output (Map)" zu finden sein könnte. Kennt sich vielleicht damit jemand aus und weiß wie man da ran kommt?

    Das Problem ist, dass C++ keinen derartigen Mechanismus zur Verfügung stellt. Wenn du meinst dass dein Compiler das trotzdem kann, solltest du wenigstens mal erwähnen, um welchen Compiler es überhaupt geht.
    Obwohl - die Art der Fragestellung, die gestellte Aufgabe und das Nicht-erwähnen des Compilers, das deutet alles eindeutig auf Visual C++ hin. 🙂



  • @troll
    Ja ich benutze Visual Studio Professional 6 mein Programm läuft mit den MFC.

    @pumuckl
    mir ist schon klar das ich damit die Adresse bekomme, allerdings wird ein größerer Speicherbereich reserviert. Ich würde jetzt nicht erwarten das der nächste reservierte Speicherbereich bei 1241468 beginnt wenn doch zuvor in 1241464 geschrieben wurde. Der Wert von pSV1 ist nach der Initialisierung genau derselbe wie zuvor beim Anlegen des Pointers! Und der geringe Abstand im Speicher zum nächsten macht mich ja gerade stutzig. 2 * 2Byte * 8192 das müsste einen wesentlich größeren Speicherplatz belegen...

    CString adr;
    adr.Format("%d", &pSV);
    m_List.InsertItem (0, adr);
    

    vielleicht geht auch etwas bei der Konvertierung in einen String schief...



  • Ich bin jetzt nochmals mit dem Debugger durchgegangen und stelle fest, das nach der Initialisierung doch meine erwarteten Adressen kommen. Das Problem muss also in der Konvertierung liegen. Die Adressen sind ja hexadezimal, weiß vielleicht jemand wie ich sie passend als String, am besten so wie sie im Speicher stehen (0x0015e010), ausgeben kann?

    MfG

    cappasa



  • &pSV ergibt aber die Adresse von pSV und nicht die Adresse des Speicherbereichs. lass den Aressoperator weg und gib einfach den Wert von pSV aus, das ist die Adresse des Speichers den du allokiert hast.



  • @pumuckl

    ja danke nochmals, habs aber seit geraumer Zeit auch heraus gefunden, den Referenzoperator habe ich weggelassen und den Platzhalter mit %x für hexadezimale Ausgabe gesetzt.
    Mit GetDataType übergebe ich nun die WAVEHDR Struktur und nType stellt die ausgewählte Zeile meiner Liste dar. So caste ich den aktuellen Datenpuffer auf den entsprechenden Datentyp.
    Zu Beginn lege ich alle 5 Signalvektoren an und allokiere sie, sobald einer ausgewählt wurde, werden die übrigen 4 freigegeben und der gewählte Signalvektor wird mittels GetDataType in pDP.x1 (Linker Channel zum Zeichnen) geschrieben. ( pDP.x1 = GetDataType(lpwh, m_nSV); )

    void* CWiwoDlg::GetDataType(LPWAVEHDR lpwh, int nType)
    {
    	switch(nType)
    	{
    	case 1:
    		return (short int*)lpwh->lpData;
    	case 2:
    		return (int*)lpwh->lpData;
    	case 3:
    		return (long int*)lpwh->lpData;
    	case 4:
    		return (float*)lpwh->lpData;
    	case 5:
    		return (double*)lpwh->lpData;
    	default:
    		return (short int*)lpwh->lpData;
    	}
    }
    

    MfG Cappaja



  • Das Ganze in Kurz:

    void* CWiwoDlg::GetDataType(LPWAVEHDR lpwh, int nType)
    {
        return lpwh->lpData;
    }
    


  • @troll

    aber so übergebe ich pDP.x1 immer einen LONG Pointer. Ich will doch unterschiedliche Datentypen übergeben. Meine Liste befindet sich in einem extra Dialog auf welchen ich mit m_pSignal zugreife. Ich brauche ja die darin angelegten Signalvektoren sodass pDP.x1 diejenige Adresse besitzt, welche in der Liste ausgewählt wurde. Oder habe ich wo einen Denkfehler? Oder sollte ich auf den Rückgabetyp ganz verzichten und einfach die jeweilige Operation ausführen? also statt return gleich die Initialisierung in (pDP.x1 = m_pSignal->pSV1)

    void* CWiwoDlg::GetDataType(LPWAVEHDR lpwh, int nType)
    {
    	if(m_pSignal != NULL)
    	{
    		switch(nType)
    		{
    		case 1:
    			m_pSignal->pSV1 = (short int*)lpwh->lpData;
    			return m_pSignal->pSV1;
    		case 2:
    			m_pSignal->pSV2 = (int*)lpwh->lpData;
    			return m_pSignal->pSV2;
    		case 3:
    			m_pSignal->pSV3 = (long int*)lpwh->lpData;
    			return m_pSignal->pSV3;
    		case 4:
    			m_pSignal->pSV4 = (float*)lpwh->lpData;
    			return m_pSignal->pSV4;
    		case 5:
    			m_pSignal->pSV5 = (double*)lpwh->lpData;
    			return m_pSignal->pSV5;
    		default:
    			m_pSignal->pSV1 = (short int*)lpwh->lpData;
    			return m_pSignal->pSV1;
    		}
    	}
    	else
    		return (short int*)lpwh->lpData;
    }
    


  • Ich blicke bei deinem Kram da nicht so recht durch, aber die Grundregel lautet: einem void* -Pointer kann man jeden anderen Pointer-Typ ohne Cast zuweisen. In die andere Richtung gehts natürlich nicht ohne Cast.
    In C++ gibts übrigens mehrere Casting-Operatoren, z. B. static_cast und reinterpret_cast , mit jeweils eigener Semantik. Auf die weniger ausdrucksstarken C-Style Casts sollte man verzichten.


Anmelden zum Antworten