23 Ekim 2017 Pazartesi

Variadic Function

Giriş
Variadic Function değişken sayıda parametre alabilen metod anlamına gelir. 

Variadic Function Tarihçesi
Açıklaması şöyle. İlginç bir şekilde C diline girmeden önce C++'ta kullanılmış.
To add to the other answers, the func(arg, ...) syntax first developed in C++, and then was incorporated into the ANSI C standard, sometime between 1984 and 1988.
Variadic Parametreler Nasıl Geçilirler
Bu konuda C++ standardı bir açıklama getirmiyor. Derleyiciler kendi çözümlerini üretmişler.  Cevapta stack kullanılması açıklanmış.

Non-POD Type
non-pod tiplerin - örneğin bir sınıf - variadic parametre olarak geçilmesi tanımsız davranış. Yani yapılmaması gerekir. Açıklaması şöyle
You cannot pass non-POD types to C-style variadic functions
Macrolar
va_list, va_start, va_end,va_arg macroları için  şu satırı dahil ederiz.
#include <stdarg.h>
va_list macrosu
Önce bir metod tanımlarız. Şöyle yaparız.
void setList(int count, ...) {
  ...
}
Metodun içinde parametreleri okumak için bir liste oluştururuz. Şöyle yaparız.
void setList( int count, ... ) {
  va_list numbers;
  va_start (numbers, count);
  ...
  va_end (numbers);
}
va_start macrosu va_list değişkenine yazdığı için va_list memset ile sıfırlamaya gerek yok. Şu kod fazladan iş yapıyor.
va_list args;
memset(&args, 0, sizeof(va_list));

va_start(args, xxx);
...
va_end(args);
va_start macrosu - va_list + int
İmzası şöyle
void va_start(va_list ap, last);
Açıklaması şöyle.
The va_start() macro initializes ap for subsequent use by va_arg() and va_end(), and must be called first.
Açıklaması şöyle.
2 The va_start macro shall be invoked before any access to the unnamed arguments.

3 The va_start macro initializes ap for subsequent use by the va_arg and va_end macros. Neither the va_start nor  va_copy macro shall be invoked to reinitialize ap without an intervening invocation of the va_end macro for the same ap .
Şöyle yaparız.
void setList(int count, ... ) {
  va_list numbers;
  va_start (numbers, count);
  ...
  va_end (numbers);
}
va_start macrosu - va_list + char *
Şöyle yaparız.
void debug(int msglevel, const char *fmt, ...)
{
  va_list va;
  va_start(va, fmt);
  vfprintf(stderr, fmt, va);
  va_end(va);
}
va_end macrosu
Aynı metod için listeyi temizlememiz gerekir. Açıklaması şöyle
Each invocation of va_start() must be matched by a corresponding invocation of va_end() in the same function.
va_arg macrosu - int
Parametreye va_arg ile şöyle erişiriz.
for(int n = 0; n < count; n++)
  int num = va_arg(numbers, int);
Bazı Önemli Variadic Metodlar
printf
printf yazısına taşıdım.

vsnprintf
vsnprintf yazısına taşıdım.

vfprintf
Şu satırı dahil ederiz.
#include <cstdio>
Şöyle yaparız.
void debug(int msglevel, const char *fmt, ...)
{  
  va_list va;
  va_start(va, fmt);
  vfprintf(stderr, fmt, va);
  va_end(va);
}
Array Geçmek
Variadic Function yerine array geçmek daha kolay olabilir.

C++
C++'ta Variadic Function'ların bence yeri yok. Artık kullanılmamalı. st::array, std::vector, std::initializer_list ve hatta variadic template bile kullanılabilir.

Hiç yorum yok:

Yorum Gönder