Tiendo a evitar varargs excepto en una circunstancia específica donde es muy útil. Los argumentos variables en realidad no ofrecen mucho beneficio por encima de lo que se puede hacer mediante llamadas a funciones individuales, especialmente en su caso.
En términos de legibilidad (y eso es generalmente lo que prefiero sobre la velocidad bruta, excepto en casos muy específicos), no hay diferencia real entre las dos opciones siguientes (He agregado un conteo a las versiones varargs ya que necesita una contar o centinela para detectar el final de los datos):
update(2, FIELD_NAME1, 10, FIELD_NAME2, 20);
update(3, FIELD_NAME3, 10, FIELD_NAME4, 20, FIELD_NAME5, 30);
/* ========== */
update(FIELD_NAME1, 10);
update(FIELD_NAME2, 20);
update(FIELD_NAME3, 10);
update(FIELD_NAME4, 20);
update(FIELD_NAME5, 30);
de hecho, como la versión varargs se hace más largo, tendrá que dividirlo todos modos, para el formato:
update(5,
FIELD_NAME1, 10,
FIELD_NAME2, 20,
FIELD_NAME3, 10,
FIELD_NAME4, 20,
FIELD_NAME5, 30);
Hacer es el resultado de "una llamada por nombre de campo" en un código más simple i n la función en sí misma, y no degrada la legibilidad de las llamadas. Además, permite que el compilador detecte ciertos errores que no puede hacer para varargs, como tipos incorrectos o una discrepancia entre el recuento proporcionado por el usuario y el recuento real.
Si realmente debe ser capaz de llamar a una función única de hacerlo, me gustaría optar por:
void update (char *k1, int v1) {
...
}
void update2 (char *k1, int v1, char *k2, int v2) {
update (k1, v1);
update (k2, v2);
}
void update3 (char *k1, int v1, char *k2, int v2, char *k3, int v3) {
update (k1, v1); /* or these two could be a single */
update (k2, v2); /* update2 (k1, v1, k2, v2); */
update (k3, v3);
}
/* and so on. */
Incluso se puede hacer las funciones de nivel superior como macros, si lo prefiere, sin perder seguridad tipo.
El único lugar donde suelo usar funciones varargs es cuando proporciono la misma funcionalidad que printf()
- por ejemplo, ocasionalmente he tenido que escribir logging libraries con funciones como logPrintf()
que proporcionan la misma funcionalidad. No puedo pensar en cualquier otra vez en mi larga (y quiero decir, larga :-) vez en la coalface que he necesitado para usarla.
Como un lado, si decides usar varargs, tiendo a usar centinelas en lugar de conteos ya que esto evita discrepancias al agregar campos. Desde aquí se puede olvidar para ajustar el recuento y terminar con:
update (2, k1, v1, k2, v2, k3, v3);
al agregar, que es insidioso, ya que en silencio se salta K3/v3, o:
update (3, k1, v1, k2, v2);
cuando se eliminan, lo que es casi seguro fatal para el funcionamiento exitoso de su programa.
Tener un centinela evita que esto (siempre y cuando que no se olvide el centinela, por supuesto):
update (k1, v1, k2, v2, k3, v3, NULL);
luego pase una cadena grande en un formato conocido. Las cadenas son más serializables y muy portátiles. Solo tiene que definir un formato para pasarlos - XMl es uno (aunque pesado), o simplemente lo haría una csv simple. – gbjbaanb
+1 a gbjbaanb - mira (x) printf - la implementación más hermosa de los varags conocidos :) – KevinDTimm