Zugriff auf Speicherbereich von Rückgabewert ANSI C



  • 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



  • Gargoyl schrieb:

    Wenn i deklariert wird, verbraucht sie zwangläufig Speicher unabhängig davon wie oft diese es verwendet wird.

    Du kannst i eliminieren, indem du einen Zeiger hochzählst, wie von DirkB gezeigt. Aber ob das wirklich weniger Stackspeicher oder weniger Zeit verbraucht, ist nicht so leicht zu sagen, weil die Compiler mittlerweile oft schlau genug sind, solche Sachen zu verstehen und dementsprechend vernünftigen Code erzeugen.

    Gargoyl schrieb:

    Lt. meinem Kompiler listing wird für die Deklaration einer Funktion mit dem Rückgabewert char automatisch ein byte im Ram reserviert.

    Da kann was nicht stimmen, weil so kleine Funktionen die ersten Kandidaten für das Inlining sind.

    Gargoyl schrieb:

    also muss man es wohl anders deklarieren oder halt doch ein Stückchen Assembler schreiben...

    Gib mal ein Testbeispiel, dann können wir nachsehen, ob und wie viel besser deine händische Variante auf unseren Systemen sein wird.



  • Das ist zwar nicht das was ich will aber um einiges kompakter als den kram den der Kompiler erzeugt:

    unsigned char test( unsigned char* msg)
    {
       int i;
      __asm
      {
        mov eax, 0     
        mov ebx, msg   
    
    TEST_LOOP:    
        cmp [ebx], 0x30
    
        je TEST_ENDE
    
        inc eax    
        inc ebx    
        jmp TEST_LOOP
    TEST_ENDE:
        mov i, eax   
      }
      return i;      //nret zurückgeben
    }
    

    aber mein eigenltiches Ziel ist ja den platz mit C Source zu sparen und nicht durch asm zu ersetzten...


Anmelden zum Antworten