2010-08-06 4 views
1

je la fonction suivante:VA-args ne résout pas correctement

void Register(Data* _pData, uint32 _Line, const char* _pFile, ...) 
{ 
    va_list Args; 
    va_start(Args, _pFile); 
    for(uint i = 0;i m_NumFloats; ++i) 
    { 
     _pData->m_Floats[i] = va_arg(Args, fp32); 
    } 
    va_end(Args); 
} 

qui est appelé par la macro:

#define REG(_Name, ...)\ 
{\ 
    if(s_##_Name##_Data.m_Enabled) 
     Register(&s_##_Name##_Data, __LINE__, __FILE__, ##__VA_ARGS__);\ 
}\ 

Avec l'utilisation:

REG(Test, (fp32)0.42f); 

Le Data- struct ressemble à:


struct Data 
{ 
    int m_NumFloats; 
    fp32 m_Floats[4]; 
} 

La macro de création de données crée le Data g_YourName_Data statique et l'initialise correctement avec un maximum de 4 m_NumFloats.

L'appel va_arg résout à 0.0. s_Test_Data existe et la fonction Register est appelée appropriée. va-list ne me laisse tout simplement pas résoudre le premier argument dans le flotteur dans lequel je l'ai passé. Y a-t-il quelque chose de spécifique qui me manque?

+2

Qu'est-ce que '_Name_Data'? Pourquoi déclarez-vous le paramètre '_Name' dans votre macro, quand votre définition de macro n'utilise pas' _Name' nulle part? Que fait '##' en face de '__VA_ARGS__'? – AnT

+0

Il n'y a pas de '_Name_Data'. C'est une macro utilisant '_Name' pour trouver un objet déclaré statiquement qui dans ce cas se développe en' _Test_Data'. Donc, la macro utilise '_Name'. Le '##' est utilisé pour enlever le ',' si aucun paramètre supplémentaire n'est passé. – Simon

+0

@AndreyT "Que fait ## devant" __VA_ARGS__'? " - il permet à une macro variadique de recevoir zéro argument. –

Répondre

2

Essayez:

#define REG(_Name, ...)\ 
{\ 
    if(s_##_Name_Data.m_Enabled)\ 
     Register(&s_##_Name_Data, __LINE__, __FILE__, __VA_ARGS__);\ 
} 

Débarrassez-vous de l'opérateur-coller de jeton. Vous nous manquons également un '\' dans votre macro (peut-être une erreur copy-n-paste?).

De même, utilisez va_arg(), et non va_args(). Et je ne suis pas sûr si vous vouliez que _Name soit _Name_Data ou l'inverse.

Enfin, j'ai supposé que fp32 était un alias pour float; GCC avait ceci à me dire:

C:\TEMP\test.c:22: warning: `fp32' is promoted to `double' when passed through `...' 
C:\TEMP\test.c:22: warning: (so you should pass `double' not `fp32' to `va_arg') 
C:\TEMP\test.c:22: note: if this code is reached, the program will abort 

Vous devriez tenir compte de cet avertissement. Le programme plante pour moi si je ne le fais pas.

+3

L'objet ', ## __VA_ARGS__' est une extension GCC qui fait disparaître la virgule si' __VA_ARGS__' ne se transforme en aucun jeton (c'est-à-dire si REG() est appelé avec un seul argument). Dans ce cas, cela n'est pas approprié car Register() doit recevoir au moins un argument anonyme, et vous aimeriez que ce soit une erreur de compilation plutôt qu'une erreur lors de l'exécution, mais ce n'est pas automatiquement faux. – zwol

+0

@Zack - merci pour cette information. Je savais que le CCG avait un moyen de gérer le '__VAR_ARGS__' vide, mais ne me rappelais pas que c'était ça. –

+0

Merci pour la réponse Michael, et désolé pour les erreurs de copier-coller. Je vais modifier le post pour le rendre correct. Je ne reçois pas de tels avertissements. Le vrai code gère le cas où aucun va-args n'est présent, le nombre d'arguments attendus est défini plus tôt. Voudriez-vous vraiment ajouter un '\' sur la dernière ligne de la macro?Je suis tout à fait certain que vous n'en avez pas besoin (puisque j'ai plusieurs macros qui ne l'ont pas et cela aurait causé des erreurs de compilation si ce n'est pas le cas). '_Name 'est inséré dans l'identifiant auquel nous accédons. Dans ce cas, l'identificateur deviendrait 's_Test_Data'. – Simon

Questions connexes