Zugriff auf Speicherbereich von Rückgabewert ANSI C



  • Hallo,

    ich hab mal ne generelle Frage:
    Hat man die Möglichkeit direkt auf den Speicherbereich des Rückgabewertes zuzugreifen?

    Als veranschaulichendes Beispiel was ich meine:

    normale Varriante:

    unsinged char test ( unsigned char *msg)
    {
    unsigned char i = 0;
    while ( msg[++i] != 0x30);
    return i;
    }

    int main ( void )
    {
    unsigned char msg[]="Hallo ";
    unsigned char ergebnis;
    ergebnis = test(msg);

    printf("%i",ergebnis);
    }

    So die Funktion würde ich gerne ersetzen wollen...
    jetzt der Fragwürdige Teil, wo ich nicht weiß ob es geht und wenn ja wie (ein wenig pseudocode):

    unsinged char test ( unsigned char *msg)
    {
    *this = 0;
    while ( msg[++this] != 0x30);
    return this;
    }

    über eine Lösung würd ich mich freuen

    🙂



  • Gargoyl schrieb:

    Hat man die Möglichkeit direkt auf den Speicherbereich des Rückgabewertes zuzugreifen?

    Muss der denn einen Speicherbereich haben?



  • Was für ein Typ ist this?

    *this = 0; läßt auf einen Zeiger schließen.
    msg[++this] und return this; auf unsinged char.

    Vielleicht meinst du ja sowas:

    unsinged char* test ( unsigned char *msg)
    {
      while ( *msg != 0x30) msg++;
      return msg;
    }
    


  • also er hat ja welche, wenn ich eine Funktion definiere wie:

    unsigned char test ( unsigned char *msg)

    hat diese automatisch mindestens 2 Speicherbereiche im ram, einmal einen Pointer für msg und einmal ein byte in dem der rückgabewert am ende steht.

    in der Theorie müsste es doch eine Möglichkeit geben wie man dierekt auf das Byte was für die Rückgabe, welches ja sowieso reserviert wurde, zuzugriefen.



  • also this soll im Beispiel den Zugriff auf das Rückgabebyte darstellen.



  • BITTE nutzt doch C/C++ code tags..

    Also klar ist das was du machen willst möglich, nur wozu?
    Und dann wird der Wert beim Aufruf von return ja auch noch überschrieben, du müsstest also entweder mit threads und/oder zwei Prozessen arbeiten.



  • Gargoyl schrieb:

    also er hat ja welche, wenn ich eine Funktion definiere wie:

    unsigned char test ( unsigned char *msg)

    hat diese automatisch mindestens 2 Speicherbereiche im ram, einmal einen Pointer für msg und einmal ein byte in dem der rückgabewert am ende steht.

    Und wenn der Compiler sie lieber inlinen würde?



  • Erstens hat der Rückgabewert nicht zwangsläufig ein Byte und zweitens muss dafür auch nicht Speicher reserviert werden. Wenn du eine Konstante zurückgibst (oder der Compiler so optimiert, dass erst garkeine lokale Variable auf dem Stack angelegt wird), dann wird einfach nur der Rückgabewert auf den Stack gepusht und zurückgesprungen oder der Wert (bzw. Zeiger darauf) in ein Register (je nach Typ meistens EAX, EDX:EAX etc.) kopiert.

    Ansonsten versteh ich nicht, wozu du sowas brauchst.



  • Gargoyl schrieb:

    also er hat ja welche, wenn ich eine Funktion definiere wie:

    unsigned char test ( unsigned char *msg)

    hat diese automatisch mindestens 2 Speicherbereiche im ram, einmal einen Pointer für msg und einmal ein byte in dem der rückgabewert am ende steht.

    in der Theorie müsste es doch eine Möglichkeit geben wie man dierekt auf das Byte was für die Rückgabe, welches ja sowieso reserviert wurde, zuzugriefen.

    Dieses Byte kann aber auch in einem Register liegen und hat damit überhaupt keine Adresse. Das was Du willst, geht nicht und ist auch nicht sinnvoll.

    Edit: Erkläre doch mal, warum Du das machen willst.



  • Der Amtsweg schrieb:

    return-[i]type[/i] function_name (parameter list)
    {
     body of function
    }
    

    Der "type" hat keine Adresse. Ablesung undurchführbar.



  • Rückgabewerte werden, abgesehen von Floating points, generell in Registern gespeichert.
    Bei gängigen auf x86 basierenden PCs immer in al, ax, eax, edx:eax(bei 32 bit cpu und 64 bit rückgabetyp) oder rax(bei 64 bit cpu und 64 bit rückgabetyp)

    Bei einer einfachen Funktion wie deiner braucht für den Zähler überhaupt kein Platz auf dem Stack reserviert werden und das sollte der Compiler auch erkennen können.



  • DrakoXP schrieb:

    Rückgabewerte werden, abgesehen von Floating points, generell in Registern gespeichert.

    na aber klar 😉



  • Schau die die verschiedenen Calling Conventions (cdecl, stdcall, fastcall, thiscall) an und du wirst mir zustimmen.

    Zu den internen Vorgängen im clrcall konnte ich auf die Schnelle nichts detailiertes finden (clrcall ist aber auch nur für C++/CLI relevant).

    Und ja, Sprachen, deren Bytecode von VMs ausgeführt wird (Java, .Net-Sprachen), sowie interpretierte Sprachen werden wahrscheinlich Rückgabewerte nicht direkt über dir Register zurückgeben.

    Aber zumindest C und C++ verwenden Register für Rückgabewerte.



  • DrakoXP schrieb:

    Aber zumindest C und C++ verwenden Register für Rückgabewerte.

    Und was passiert im folgenden Beispiel mit der Rückgabe (falls sie nicht wegoptimiert wird)?

    typedef struct{char[1000] arr;} Too_big_for_register;
    
    Too_big_for_register func(void)
    {
        Too_big_for_register ret;
        return ret;
    }
    


  • das wird auf den stack gepusht -.-

    allerdings ist aus performance gründen solches design nicht zu empfehlen.
    hier sollte man dann doch eher einen pointer zurückgeben, der dann wieder in ein register passt.



  • func(void) wird mit einem verstecken Parameter aufgerufen. Der versteckte Parameter ist ein Zeiger auf "genug" Speicherplatz, um den Inhalt von ret aus func() aufzunehmen.



  • merker schrieb:

    func(void) wird mit einem verstecken Parameter aufgerufen. Der versteckte Parameter ist ein Zeiger auf "genug" Speicherplatz, um den Inhalt von ret aus func() aufzunehmen.

    Und worauf zeigt dieser Parameter-Zeiger? Heap oder Stack?



  • Wenn sie "xxx = func()" aufgerufen wird, ist der versteckte Parameter die Adresse von xxx. Je nach dem wie/wo xxx definiert wurde, ist es Heap oder Stack.

    Wenn sie nur "func()" aufgerufen wird, zeigt der Parameter auf Stack, den der Aufrufer (also die "umgebende" Funktion) bereitstellen muß.



  • Hallo,
    also der Sinn dahinter besteht darin das ich gerne die Reservierung von temporären Variablen wie in diesem Beispiel "i" weglassen möchte.
    Wenn i deklariert wird, verbraucht sie zwangläufig Speicher unabhängig davon wie oft diese es verwendet wird.
    Lt. meinem Kompiler listing wird für die Deklaration einer Funktion mit dem Rückgabewert char automatisch ein byte im Ram reserviert.
    Sprich es muss einen Speicherbereich geben in den der Rückgabewert, sofern er dynamisch erzeugt ist, hinterlegt wird ( Die Rückgabe eines Festen Werts ist ausgeschlossen).
    Und ja, ich will Ramspeicher sparen indem ich temporäre Variablen weglasse,...
    Ob es für den einzelnen Sinn macht sei dahingestellt, ich möchte lediglich in Erfahrung bringen ob dies möglich ist.
    Der Compiler linkt den Code leider nicht so wie ich es gerne hätte, also muss man es wohl anders deklarieren oder halt doch ein Stückchen Assembler schreiben...



  • Meinst du sowas?

    inline DWORD_PTR GetCPUFlags() // edx Register
    {
    	_asm
    	{
    		mov    eax, 1
    		cpuid 
    		mov    eax, edx 
    	}
    }
    int main()
    {
    	if(GetCPUFlags() & (1<<25))
    		puts("SSE wird von der CPU unterstuetzt!");
    }
    

    Edit: Klappt so nur mit dem MSVC


Log in to reply