Undefinierte Parameteranzahl / Funktionsgröße auf Stack bestimmen



  • FrEEzE2046 schrieb:

    Bashar schrieb:

    Das geht nicht. Die Funktion muss das aus den Pflichtparametern irgendwie ermitteln, bei printf z.B. aus den Formatspecifiern.

    Das MUSS ja irgendwie gehen.

    Warum?
    Der Aufbau eines HugeStrings in Turbopascal ist übrigens unabhängig davon, ob er an eine Funktion übergeben wird oder nicht.

    In C liegt die Information über die Anzahl der übergebenen Parameter eben NICHT auf dem Stack. Es würde auch nicht viel nützen, weil auch eine Information über die Größe der Parameter (char, int, long?) NICHT übergeben wird.



  • Belli schrieb:

    Warum?
    Der Aufbau eines HugeStrings in Turbopascal ist übrigens unabhängig davon, ob er an eine Funktion übergeben wird oder nicht.

    Das habe ich nie anders behauptet! Da hast du was falsch verstanden.

    Belli schrieb:

    In C liegt die Information über die Anzahl der übergebenen Parameter eben NICHT auf dem Stack. Es würde auch nicht viel nützen, weil auch eine Information über die Größe der Parameter (char, int, long?) NICHT übergeben wird.

    Sie liegt vlt. nicht auf dem Stack, dennoch muss sie irgendwo sein. Wie funktioniert denn sonst oben genanntes:

    int main( int argc, char* argv[] ) {}
    

    Wie kommt main denn an argc? Wenn dies ebenfalls mit den genannten Makros funktionert, dann bleibt die Frage, WIE diese Makros funktionieren. Das muss ja auch irgendwie an die Information kommen. Wenn diese aber "nirgendwo liegt", dann könnte auch das Makro nicht funktionieren ...



  • FrEEzE2046 schrieb:

    Das MUSS ja irgendwie gehen. Die Information muss irgendwo auf dem Stack liegen.

    Tut sie eben NICHT. Und wenn Du nur einen Char- Parameter da liegen hast, kannst Du 5000 doubles auslesen - natürlich 5000- mal Datenmüll.

    FrEEzE2046 schrieb:

    Ich gehe von einem Ansatz wie bei einem HugeString in TurboPascal aus.

    C != TurboPascal.

    FrEEzE2046 schrieb:

    In Delphi gibt es dafür ja auch High() und Low() die die größe eines (auch dynamischen!) Arrays ermitteln.

    C != Delphi.
    In C wird Dir nur die Adresse des Frameblocks weitergegeben, sonst nichts. Alles Weitere = Eigenimplementation.



  • FrEEzE2046 schrieb:

    Wie kommt main denn an argc? Wenn dies ebenfalls mit den genannten Makros funktionert, dann bleibt die Frage, WIE diese Makros funktionieren. Das muss ja auch irgendwie an die Information kommen. Wenn diese aber "nirgendwo liegt", dann könnte auch das Makro nicht funktionieren ...

    Du willst nicht verstehen?
    argc wird von Außen an main gegeben, damit main weiß, wieviele char * da zu lesen sind. Könnte main das selber feststellen, wäre argc unnötig!!!!!



  • FrEEzE2046 schrieb:

    Sie liegt vlt. nicht auf dem Stack, dennoch muss sie irgendwo sein.

    Ja, irgendwo ist sie ... implizit. Der Aufrufer und die Funktion müssen sich irgendwie einig werden, wie die Information zu der Funktion kommt. Bei printf geschieht das über den Formatstring, printf hat aber keine Möglichkeit zu prüfen, ob der Aufrufer lügt und mehr oder weniger Argumente übergibt als dort spezifiziert sind!

    Wie funktioniert denn sonst oben genanntes:

    int main( int argc, char* argv[] ) {}
    

    Wie kommt main denn an argc?

    Das ist doch was vollkommen anderes. main hat keine variable Parameterliste, außerdem wird main in argc die (Kommandozeilen-)Parameteranzahl, also die Länge eines Arrays, übergeben. Was hat das denn mit deiner Frage zu tun?



  • pointercrash() schrieb:

    argc wird von Außen an main gegeben, damit main weiß, wieviele char * da zu lesen sind. Könnte main das selber feststellen, wäre argc unnötig!!!!!

    Bashar schrieb:

    Das ist doch was vollkommen anderes. main hat keine variable Parameterliste, außerdem wird main in argc die (Kommandozeilen-)Parameteranzahl, also die Länge eines Arrays, übergeben. Was hat das denn mit deiner Frage zu tun?

    Die Frage ist doch einfach, WIE wird denn "von außen" argc an main gegeben. Wie kann ich mir das denn vorstellen?

    Was das mit meiner Frage zu tun hat? Natürlich ist char* argv[] etwas anderes als eine undefinierte Parameterliste, aber auch ein dynamisches array wäre vom Ansatz her ja eine genau so mögliche Implementierungsmöglichkeit. Beides läuft auf das selbe Ziel hinaus: Mehrere Parameter eines gleichen Typs übergeben und deren Anzahl herausfinden ... (ja, ich weiß, dass ein dyn. array auch nur 1 Parameter ist) ...



  • FrEEzE2046 schrieb:

    Wie funktioniert denn sonst oben genanntes:

    int main( int argc, char* argv[] ) {}
    

    Wie kommt main denn an argc?

    der startup-code ruft 'main' auf und übergibt den wert. das ist ja auch keine va-list.
    🙂



  • FrEEzE2046 schrieb:

    Die Frage ist doch einfach, WIE wird denn "von außen" argc an main gegeben. Wie kann ich mir das denn vorstellen?

    ist nicht vergleichbar und der mechanismus ist afaik nicht definiert. das betriebsystem wird wohl den kommandozeilen-string in einzelne teilstrings parsen und mitzählen, wie viele freie leerzeichen da drin sind. das ist dann dein argc.

    gib deiner funktion einfach einen parameter mit, wie viele argumente mitgeschickt wurden. die typen weißt du dann zwar immer noch nicht, aber die anzahl ist dann bekannt.



  • vadda schrieb:

    gib deiner funktion einfach einen parameter mit, wie viele argumente mitgeschickt wurden. die typen weißt du dann zwar immer noch nicht, aber die anzahl ist dann bekannt.

    Naja, der typ ist schon definiert. Sowohl bei undef. Parameterliste, als auch bei einem dyn. Array (wenn`s denn kein void* ist).

    Das mit dem Mitzählen der leeren Stellen von main ist eine logische Erklärung. Bei der Geschichte mit den undef. Parametern bleibt aber die Frage, wie genau das ganze denn letztendlich ausschaut.

    Kurz gefragt: Ist eine undef. Paramererliste im Sinne von int x,... im Prinzip (auf dem Stack) nichts anderes als ein array aus Integern?

    Zudem ist die Frage wie gesagt, wie genau va_list denn an den Wert kommt. Was genau macht das Makro denn?

    Ich will nicht kleinkariert sein und ich verstehe und weiß auch was ihr hier alle gesagt habt (übrigens danke für die vielen Reaktionen).
    Es ist lediglich Wissensdurst, es interessiert mich einfach. Ich möchte wissen, wie sieht denn int x,... auf dem Stack aus (ist es ein Pointer?) und was macht va_list.

    Wenn mir da jemand helfen könnte, wäre mir sehr geholfen ... (intelligenter Satz).

    Das Delphi/TurboPascal/ObjectPascal kein C/C++ ist, ist mir auch klar. Aber wenn Borland es auf die Reihe bekommt eine Funktion zu implementieren, die auch die Größe von dyn. Arrays ermittelt, wird dies jawohl auch in C/C++ und in Assembler sowieso möglich sein.



  • [quote="FrEEzE2046"]

    vadda schrieb:

    Naja, der typ ist schon definiert. Sowohl bei undef. Parameterliste, als auch bei einem dyn. Array (wenn`s denn kein void* ist).

    Das mit dem Mitzählen der leeren Stellen von main ist eine logische Erklärung. Bei der Geschichte mit den undef. Parametern bleibt aber die Frage, wie genau das ganze denn letztendlich ausschaut.

    Kurz gefragt: Ist eine undef. Paramererliste im Sinne von int x,... im Prinzip (auf dem Stack) nichts anderes als ein array aus Integern?

    Nein, der Typ ist nicht definiert.
    Eine Funktion, die so deklariert ist:

    void funk(int x, ...);

    kennt nur den Typ des ersten Parameters. Die weiteren übergebenen Parameter können alle einen unterschiedlichen Typ haben.



  • Belli schrieb:

    Nein, der Typ ist nicht definiert.
    Eine Funktion, die so deklariert ist:

    void funk(int x, ...);

    kennt nur den Typ des ersten Parameters. Die weiteren übergebenen Parameter können alle einen unterschiedlichen Typ haben.

    Darum geht es mir zwar eigentlich nicht, aber dass was du da sagst ist mir absolut neu. Ich habe es an dieser Stelle auch gleich mal ausprobiert:

    void funk(int x, ...) {}
    

    bringt bei mir nach Aufruf

    int main() 
    { 
         double d = 2.3;
         funk( 3, d, "Hallo" );
    
         return 0;
    }
    

    folgende Meldungen:
    error C2664: 'TestSumme': Konvertierung des Parameters 3 von 'const char [6]' in 'int' nicht möglic 122
    Warnung 1 warning C4244: 'Argument': Konvertierung von 'double' in 'int', möglicher Datenverlust 122

    Demnach muss wohl doch alles int sein, so wie ich sagte ...



  • FrEEzE2046 schrieb:

    Aber wenn Borland es auf die Reihe bekommt eine Funktion zu implementieren, die auch die Größe von dyn. Arrays ermittelt, wird dies jawohl auch in C/C++ und in Assembler sowieso möglich sein.

    geht ja auch, aber du musst es eben selbst programmieren. in C eingebaut ist sowas nicht (wie z.b. "hello".length() in Java o.ä.)
    🙂



  • +fricky schrieb:

    geht ja auch, aber du musst es eben selbst programmieren. in C eingebaut ist sowas nicht (wie z.b. "hello".length() in Java o.ä.)
    🙂

    Genau, daher ja der Thread. Hättest du vielleicht einen Ansatz?
    Es geht mir ja gar nicht darum eine vorhandene Funktion / Makro zu benutzen, ich würde es auch selber programmieren, auch in assembler. Aber mir fehlt einfach der Ansatz ...
    vlt. hab ich mich im bisherigen Thread-Verlauf undeutlich ausgedrückt 😞

    Ich mache da jetzt schon seit Tagen dran rum. Es fehlt aber einfach das Wissen, wie das Ganze zu realisieren ist.



  • FrEEzE2046 schrieb:

    Demnach muss wohl doch alles int sein, so wie ich sagte ...

    void funk(int x, ...) { }
    
    int main()
    {
    	double d = 2.0;
    	funk(1, d, "drei");
    }
    

    VS2008 schrieb:

    1>va_test - 0 error(s), 0 warning(s)

    hätte mich auch gewundert.



  • FrEEzE2046 schrieb:

    Genau, daher ja der Thread. Hättest du vielleicht einen Ansatz?

    naja, entweder du gibst der va_list eine ende-kennung als letzten wert mit (z.b. 0, -1, oder so), oder der erste ist die anzahl.

    int summe (int x, ...)
    {
      va_list vl;
      int sum = 0;
    
      va_start (vl, x);
    
      while (x--)
        sum += va_arg (vl, int);
    
      return sum;
    }
    
    int main()
    {
      // beispiel: 4 werte, 1,2,3,-6 addieren
      printf ("%d\n", summe (4, 1,2,3,-6)); 
    }
    

    🙂



  • +fricky schrieb:

    FrEEzE2046 schrieb:

    Genau, daher ja der Thread. Hättest du vielleicht einen Ansatz?

    naja, entweder du gibst der va_list eine ende-kennung als letzten wert mit (z.b. 0, -1, oder so), oder der erste ist die anzahl.
    🙂

    Mit anderen Worten:
    Es geht NICHT!
    UND: Die Parameter können alle unterschiedlichen Typs sein.

    @TE:
    Würde es vielleicht etwas nützen, wenn es Dir hier jemand auf spanisch, italienisch, französisch oder so noch mal schreibt?



  • jupp! schrieb:

    FrEEzE2046 schrieb:

    Demnach muss wohl doch alles int sein, so wie ich sagte ...

    void funk(int x, ...) { }
    
    int main()
    {
    	double d = 2.0;
    	funk(1, d, "drei");
    }
    

    VS2008 schrieb:

    1>va_test - 0 error(s), 0 warning(s)

    hätte mich auch gewundert.

    ähm, natürlich. Irgendwie war ich jetzt beim dyn. array - einfach vergessen.

    Belli schrieb:

    @TE:
    Würde es vielleicht etwas nützen, wenn es Dir hier jemand auf spanisch, italienisch, französisch oder so noch mal schreibt?

    Das wäre wirklich super! ...

    Bleib doch mal locker. Ich verstehe schon was du meinst, aber wenn es NICHT GEHT, dann ist also va_start und va_list ein Makro, was gar nicht funktioniert oder wie? Irgendwie machen die es ja wohl auch und wie bereits erwähnt schaffen das auch andere Sprachen ... schwer vorzustellen bei einer Sache die angeblich gar nicht funktioniert.

    Verstehst du jetzt was ich meine?



  • FrEEzE2046 schrieb:

    Ich verstehe schon was du meinst, aber wenn es NICHT GEHT, dann ist also va_start und va_list ein Makro, was gar nicht funktioniert oder wie?

    nein, du hast es immer noch nicht verstanden. die va_*-makros werden entweder mit hardgecodeten typen verwendet, oder es wird ein formatstring benutzt (z.b. bei printf), in dem die anzahl und die typen der parameter kodiert sind. die information kommt also nicht von irgendwo her, sondern wird vom programmierer vorgegeben. und das musst du genauso machen, wenn dir kein besserer mechanismus einfällt.



  • FrEEzE2046 schrieb:

    Ich verstehe schon was du meinst, aber wenn es NICHT GEHT, dann ist also va_start und va_list ein Makro, was gar nicht funktioniert oder wie? Irgendwie machen die es ja wohl auch und wie bereits erwähnt schaffen das auch andere Sprachen ... schwer vorzustellen bei einer Sache die angeblich gar nicht funktioniert.

    Verstehst du jetzt was ich meine?

    DU willst die Information zur Laufzeit haben. Die MAKROS liefern die erforderlichen Informationen zur Compilezeit.
    Wenn es in zB Delphi funktioniert, daß man mit Hi und Lo (oder ähnlich) jederzeit die Größe oder Grenzen eines Arrays abfragen kann, dann heißt das, daß diese Informationen im Array gespeichert sind - wie oder wo auch immer.
    Das ist in C aber nicht so ...



  • Nachtrag:
    Lies Dich doch mal in die Funktionsweise dieser Makros ein, eventuell bringt das etwas Licht ins Dunkel.
    Mit diesen Makros holst Du innerhalb der Funktion einen Parameter vom Stack. Da Du dabei den Typ des Parameters angeben mußt, 'weiß' das Makro, wie groß der Parameter ist, und kann einen Zeiger genau so weit weiterbewegen, daß er auf den nächsten Parameter zeigt (mal so ganz grob gesprochen, ich hoffe, es ist einigermaßen verständlich).
    Die Makros stellen Dir nur einen einfachen Weg zur Verwaltung eines Zeigers in die Parameterliste zur Verfügung, sonst nix.


Anmelden zum Antworten