Advertisement
bueddl

How variable argument functions in C are work

Oct 30th, 2015
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 1.79 KB | None | 0 0
  1. /* das is der "coole" Part, wir haben folgendes:
  2.  
  3.     (type*)ptr            Zuerst wird der Typecast auf "type" evaluiert, damit
  4.                         erreichen wir, dass ein ptr +1 (oder ptr++, bzw ++ptr)
  5.                         darin endet, dass wir um sizeof(type) weiterverschieben
  6.     ++(type*)ptr        Was wir genau jetzt tun... und zwar bevor...
  7.     *(++(type*)ptr)     wir den Wert mitteles dereferenzierung zurückgeben
  8.  
  9.     Hier wird dann auch klar, wieso ein Aufruf von printf("%c", ...) auch ohne
  10.     weitere Argumente funktioniert: es wird einfach die nächste (um char)
  11.     verschobene Adresse vom Stack ausglesen (hinter dem Formatstring im Stack).
  12.  
  13.     Bei printf() und scanf() werden die Format strings dazu verwendet,
  14.     destzustellen, was wann gelesen wird, aber es sollte alles mit diesem
  15.     Macro funktionieren.
  16.  
  17.     In Ansi/ISO C gibt es hierfür den header <stdarg.h>, der die passende
  18.     Macro-Familie bereitstellt!
  19. */
  20. #define NEXT(ptr, type) *(++(type*)ptr)
  21.  
  22. double average(int N, ...)
  23. {
  24.     /* Zeiger auf erstes Element (Anzahl, eig total egal was es ist, aber
  25.        wir brauchen was um auf die richtige Stelle im Stack zu zeigen) */
  26.     void *arg_ptr = &N;
  27.     /* Hilfvariablen, total egal */
  28.     int arg_int, count;
  29.     double avg = 0;
  30.    
  31.     for (count = 0; count < N; count++) {
  32.         /* Zeiger um sizeof(int) vorschieben und aktuellen Wert zurück geben */
  33.         arg_int = NEXT(arg_ptr, int);
  34.         avg += arg_int;
  35.     }
  36.  
  37.     avg /= N;
  38.     return avg;
  39. }
  40.  
  41. void main(void)
  42. {
  43.     double avg;
  44.    
  45.     /* "Normaler" Aufruf
  46.        4 = Anzahl, Werte = 5, 10, 3, 20 */
  47.     avg = average(4, 5, 10, 3, 20); /* (5+10+3+20)/4 = 9.5 */
  48.  
  49.     /* "Geht" aber auch so, gibt nur ein falsches Ergebnis :-) */
  50.     avg = average(4, 5); /* (5+?+?+?)/4 = ??? */
  51. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement