2010-01-21 3 views
1

Je le code suivant:Arguement Variable Avec Référence de la classe Comme 1er paramètre

#include <cstdarg> 
#include <iostream> 

using namespace std; 

class a { 
}; 

void fun1(a& aa, ...) 
{ 
    va_list argp; 
    va_start(argp, aa); 
    char *p = 0; 
    while ((p = va_arg(argp, char *)) != 0) { 
     cout << p << endl; 
    } 
    va_end(argp); 
} 

void fun2(char *aa, ...) 
{ 
    va_list argp; 
    va_start(argp, aa); 
    char *p = 0; 
    while ((p = va_arg(argp, char *)) != 0) { 
     cout << p << endl; 
    } 
    va_end(argp); 
} 

int main() 
{ 
    cout << "fun2" << endl; 
    fun2("a", "1", "2", (char *)0); 
    cout << "fun1" << endl; 
    fun1(a(), "1", "2", (char *)0); 
    getchar(); 
} 

Tout fonctionne bien avec fun2. Cependant, fun1 va juste planter. Puis-je savoir comment empêcher l'écrasement tout en utilisant la référence de classe en tant que 1er paramètre?

Actuellement, il imprime:

fun2 
1 
2 
fun1 

puis crash.

Je souhaite

fun2 
1 
2 
fun1 
1 
2 
+0

Comment pensez-vous que varArgs travailler? –

+0

S'il vous plaît se référer à ma mise à jour. –

+0

vous avez dit que vous avoir dans un commentaire, donc je le prends y Vous ne pouvez pas passer à gcc? Alternativement, vous pouvez compiler du code dans une DLL et l'appeler en msvc mais je déteste cette option. –

Répondre

4

Vous ne pouvez pas utiliser un paramètre de référence en tant que dernier paramètre nommé avec va_start. La raison en est que va_start prend l'adresse du paramètre nommé pour trouver l'emplacement du reste des arguments. Cependant, prendre l'adresse d'une référence donne l'adresse de la variable pointée par la référence, pas l'adresse du paramètre lui-même. Vos options sont les suivantes:

1) changer le type de variable d'une référence en un pointeur (ou une non-référence si vous êtes OK avec une copie de la variable transmise).

2) Ajouter un paramètre obligatoire supplémentaire afin que la référence ne soit pas le dernier paramètre nommé. Le paramètre supplémentaire peut être un paramètre utile, tel que l'un des char * que vous allez transmettre à votre fonction particulière, ou il peut s'agir d'une variable fictive que vous ignorez.

3) Modifier la définition de va_start. Ce n'est pas recommandé, mais vous pouvez le faire. Voir http://support.microsoft.com/kb/119394 pour une redéfinition non portable.

+0

Ick - bonne prise Darryl. Encore une autre raison d'éviter les varargas comme la peste. –

+0

ref comme va_params semblent fonctionner avec gcc (voir ma réponse et le codepad). Bon point sur le problème d'adresse. +1 –

+0

OK. J'ai abandonné. Il n'y a pas de moyen facile de le faire. –

0

Vous passez une référence non-const à un temporaire. Changer le prototype de fun1 à:

void fun1(a const& aa, ...) 

Mise à jour:

ont pas utilisé VarArgs depuis longtemps, a raté qu'un paramètre de terminaison n'était pas passé. Voir D. Shawley's answer; vous devez passer un paramètre de terminaison si vous l'utilisez comme interface.

+0

Il crash toujours. J'utilise VC++ 2008. Est-ce que ça plante à vos côtés? –

+0

Juste vérifié sur OSX et FreeBSD; fonctionne mais par coïncidence. Vous devez passer une valeur nulle pour terminer la boucle de traitement des arguments. La meilleure approche consiste à ne pas utiliser varargs du tout. – janm

2

Il me semble que vous plantez fun2. Parce que vous appelez le va_arg trop de fois et en vissant la pile. Vous devez appeler va_arg autant de fois qu'il y a de paramètres.

+0

Non. Je plante seulement dans fun1 (Notez que ma séquence d'appel est fun2 suivie de fun1). Ma mise en œuvre se réfère à http://c-faq.com/varargs/varargs1.html –

+1

Vous remarquerez que 'fun1' n'est jamais sorti. Ainsi, votre code ne revient pas de 'fun2'. Aussi, je pense que cela met en évidence les dangers de copier-coller le code que vous ne comprenez pas. –

+0

OK. Je corrige selon le commentaire D.Shawley. Mais il crash toujours dans le fun1. –

2

Les deux fun1 et fun2 terminent la boucle lorsqu'ils rencontrent un paramètre NULL ou 0. Vous n'en passez jamais un. Changer main à:

int main() 
{ 
    cout << "fun2" << endl; 
    fun2("a", "1", "2", NULL); 
    cout << "fun1" << endl; 
    fun1(a(), "1", "2", NULL); 
    getchar(); 
    return 0; 
} 

Remarque Je n'ai pas compilé, mais il devrait fonctionner. Vous devrez peut-être suivre également janm's advice.

Mise à jour: Je me suis arrêté et y ai réfléchi à nouveau. Vous devez soit:

  1. instancier un objet de type a intérieur de main et de le transmettre ou ...
  2. Après janm's advice et changer a& aa en fun2 à a const& aa

Quand j'ai essayé de compiler l'original sous g ++, j'ai été accueilli avec l'erreur suivante:

error: invalid initialization of non-const reference of type 'a&' from a temporary of type 'a'
error: in passing argument 1 of 'void fun1(a&, ...)'

Essentiellement, vous ne pouvez pas passer une variable temporaire en tant que référence non const. Voir this SO question et this Herb Sutter GotW pour certains des détails sanglants.

+0

Merci. Il ne tombe plus sur fun2. Mais ça tombe toujours sur fun1. –

0

Je suis désolé d'entendre ce code ne fonctionne pas. Je remarque si fun2 (aa est un ptr au lieu d'un ref le code fonctionne.J'ai aussi remarqué en essayant de compiler sur gcc (via http://codepad.org/) vous passez "a" dans fun2 qui est un char * .codepad/gcc se sont plaints à ce sujet Dans le codepad, ce code fonctionne.Ce code fonctionne dans ma copie de VS2008 et bloque aussi 2010b2

Ma recommandation est d'éviter les paramètres mais je suppose que vous ne pouvez pas, donc je suggère de ne pas utiliser ref et pointeurs utilisation. Ou passer à gcc, mais je ne reviendrai pas le faire, à moins qu'il n'y a pas d'autre option (raisonnable).

#include<cstdlib> 
#include <cstdio> 
#include <ios> 
#include <iostream> 
using namespace std; 
class a { 
}; 

void fun1(a& aa, ...) 
{ 
    //cout<< "sizeof" << sizeof(aa) << "&aa == " << &aa; 
    va_list argp; 
    va_start(argp, aa); 
    char *p = 0; 
    while ((p = va_arg(argp, char *)) != 0) { 
     cout << p << endl; 
    } 
    va_end(argp); 
} 

void fun2(const char *aa, ...) 
{ 
    va_list argp; 
    va_start(argp, aa); 
    char *p = 0; 
    while ((p = va_arg(argp, char *)) != 0) { 
     cout << p << endl; 
    } 
    va_end(argp); 
} 

int main() 
{ 
    cout << "fun2" << endl; 
    fun2("a", "1", "2", 0); 
    cout << "fun1" << endl; 
    a aa; 
    //cout<< "sizeof" << sizeof(aa) << "&aa == " << &aa; 
    fun1(aa, "1", "2", 0); 
    getchar(); 
} 
Questions connexes