Comment puis-je mieux désactiver un avertissement sur les variables inutilisées?


237

J'ai une application multiplateforme et dans certaines de mes fonctions, toutes les valeurs transmises aux fonctions ne sont pas utilisées. Par conséquent, je reçois un avertissement de GCC me disant qu'il y a des variables inutilisées.

Quelle serait la meilleure façon de coder autour de l'avertissement?

Un #ifdef autour de la fonction?

#ifdef _MSC_VER
void ProcessOps::sendToExternalApp(QString sAppName, QString sImagePath, qreal qrLeft, qreal qrTop, qreal qrWidth, qreal qrHeight)
#else
void ProcessOps::sendToExternalApp(QString sAppName, QString sImagePath, qreal /*qrLeft*/, qreal /*qrTop*/, qreal /*qrWidth*/, qreal /*qrHeight*/)
#endif
{

C'est si moche mais cela ressemble à la façon dont le compilateur préférerait.

Ou dois-je affecter zéro à la variable à la fin de la fonction? (ce que je déteste parce qu'il modifie quelque chose dans le flux du programme pour faire taire un avertissement du compilateur).

Existe-t-il une manière correcte?


7
Je viens de réaliser que vous avez posé une question similaire en novembre dernier. Voilà pourquoi cela semble familier! ;) stackoverflow.com/questions/308277/…
Alex B

9
Pourquoi ne pas simplement les commenter pour les deux compilateurs? Si l'argument n'est pas utilisé sur l'un, il sera probablement inutilisé sur l'autre ...
Roger Lipscombe

12
vous devez savoir que Qt a une Q_UNUSEDmacro juste pour cela. Vérifiez-le dans la documentation.
Evan Teran

1
La solution C fonctionne également très bien en C ++: stackoverflow.com/a/3599170/1904815
JonnyJD

-Un paramètre non utilisé peut également être une option si vous pouvez avoir des drapeaux de construction spécifiques au compilateur
Code Abominator

Réponses:


327

Vous pouvez le placer dans l' (void)var;expression " " (ne fait rien) pour qu'un compilateur voit qu'il est utilisé. C'est portable entre les compilateurs.

Par exemple

void foo(int param1, int param2)
{
    (void)param2;
    bar(param1);
}

Ou,

#define UNUSED(expr) do { (void)(expr); } while (0)
...

void foo(int param1, int param2)
{
    UNUSED(param2);
    bar(param1);
}

22
+1 - je documenterais toujours pourquoi vous n'utilisez pas la variable même si elle est là.
Tobias Langner

18
C'est ainsi que le Q_UNUSEDprincipe est mis en œuvre.
Dmitry Volosnykh

11
@Cameron, vous pouvez simplement omettre le nom du paramètre en C ++. S'il est basé sur des modèles, il ne sera pas utilisé en C, vous n'avez donc pas besoin de l'astuce Cast to void.
Alex B

13
Cela #define UNUSED(expr) (void)(expr)devrait aussi fonctionner (sans le temps nécessaire).
JonnyJD

7
Je me demande comment faire cela pour un modèle variadic. Dans template<typename... Args> void f(const Args&... args)Je ne peux pas écrire (void)args;ou (void)args...;parce que les deux sont des erreurs de syntaxe.
panzi

101

Dans GCC et Clang, vous pouvez utiliser la __attribute__((unused))directive du préprocesseur pour atteindre votre objectif.
Par exemple:

int foo (__attribute__((unused)) int bar) {
   return 0;
}

1
C'est la meilleure solution pour les fonctions de rappel.
Sonic Atom

1
Également pris en charge par clang: clang.llvm.org/docs/…
Alexander


39

Votre solution actuelle est la meilleure - commentez le nom du paramètre si vous ne l'utilisez pas. Cela s'applique à tous les compilateurs, vous n'avez donc pas besoin d'utiliser le pré-processeur pour le faire spécialement pour GCC.


7
Juste pour renforcer cette réponse - vous n'avez pas besoin du #ifdef, commentez simplement les noms de paramètres inutilisés.
quamrana

4
J'ai un cas où le paramètre fait partie d'un rappel et commenter le casse interrompt la compilation (donc je ne sais pas pourquoi l' g++avertit.) Dans un tel cas, que recommanderiez-vous?
Drew Noakes

1
Imaginez une méthode virtuelle en ligne avec des paramètres inutilisés / * commenté * /, le client de l'interface ne verra pas le nom du paramètre lors de l'autocomplétion dans la plupart des IDE. Dans ce cas, la solution UNUSED () est plus pratique, mais moins propre.
cbuchart

Je pense que plus c'est simple, mieux c'est, commenter est très clair
fievel

26

Mise à jour C ++ 17

En C ++ 17, nous obtenons l'attribut [[peut-être_unused]] qui est couvert dans [dcl.attr.unused]

Le jeton d'attribut peut-être_unused indique qu'un nom ou une entité est peut-être intentionnellement inutilisé. Il doit apparaître au plus une fois dans chaque liste d'attributs et aucune clause d'argument d'attribut ne doit être présente. ...

Exemple:

 [[maybe_unused]] void f([[maybe_unused]] bool thing1,
                        [[maybe_unused]] bool thing2) {
  [[maybe_unused]] bool b = thing1 && thing2;
    assert(b);
 }

Les implémentations ne doivent pas avertir que b n'est pas utilisé, que NDEBUG soit défini ou non. —Fin exemple]

Pour l'exemple suivant:

int foo ( int bar) {
    bool unused_bool ;
    return 0;
}

Clang et gcc génèrent tous deux un diagnostic à l'aide de -Wall -Wextra à la fois pour la barre et la barre inutilisée ( voir en direct ).

Lors de l'ajout de [[peut-être_unused]], les diagnostics sont réduits au silence:

int foo ([[maybe_unused]] int bar) {
    [[maybe_unused]] bool unused_bool ;
    return 0;
}

voir en direct .

Avant C ++ 17

En C ++ 11, une forme alternative de la UNUSEDmacro pourrait être formée en utilisant une expression lambda ( via Ben Deane ) avec une capture de la variable inutilisée:

#define UNUSED(x) [&x]{}()

L'invocation immédiate de l'expression lambda doit être optimisée, dans l'exemple suivant:

int foo (int bar) {
    UNUSED(bar) ;
    return 0;
}

on peut voir dans godbolt que l'appel est optimisé loin:

foo(int):
xorl    %eax, %eax
ret

5
Vous mentionnez donc C ++ 11 et parvenez ensuite à présenter une macro?! Aie! Peut-être que l'utilisation d'une fonction serait plus propre? template <class T> inline void NOTUSED( T const & result ) { static_cast<void>(result); }Vous pouvez également utiliser un lambda dans la fonction, je suppose.
Alexis Wilke

godbolt est une excellente ressource
yano

5
[&x]{}()ne fait pas vraiment taire l'avertissement, mais transmet plutôt l'avertissement de la fonction d'appel à la lambda Cela prendra du temps jusqu'à ce que les compilateurs identifient cela comme un avertissement, mais Clang-Tidy se plaint déjà d'une variable inutilisée dans la liste de capture.
nVxx

25

Une façon encore plus propre consiste à simplement commenter les noms de variables:

int main(int /* argc */, char const** /* argv */) {
  return 0;
}

8
Ce n'est pas bon si vous disposez de doxygen et que vous souhaitez documenter les paramètres.
Alexis Wilke

18
@AlexisWilke: Cela serait considéré comme un bug dans doxygen, IMO
6502

3
Vous pouvez #definir YOUR_PROJECT_UNUSED (argname) conditionnellement sur #ifdef DOXYGEN pour que doxygen puisse voir le nom et le vrai compilateur ne le fait pas via int main (int YOUR_PROJECT_UNUSED (argc), ...). Pas fabuleux, mais ça marche.
mabraham

Je trouve très douloureux de commenter un bloc de code avec de nombreux commentaires imbriqués. (le compilateur se plaint de tout le monde).
Jeff McClintock

@JeffMcClintock utilise simplement des commentaires sur une seule ligne. La plupart des éditeurs décents prennent en charge l'édition de blocs verticaux (par exemple [Ctrl] + [V] dans Vim). Sinon, utilisez #if 0 / #endifles commentaires de bloc.
Ruslan

24

Un collègue vient de me montrer cette jolie petite macro ici

Pour plus de facilité, je vais inclure la macro ci-dessous.

#ifdef UNUSED
#elif defined(__GNUC__) 
# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) 
#elif defined(__LCLINT__) 
# define UNUSED(x) /*@unused@*/ x 
#else 
# define UNUSED(x) x 
#endif

void dcc_mon_siginfo_handler(int UNUSED(whatsig))

12
"nice" "macro" "c ++" - choix 2.
Jeff McClintock

23

ne signale pas ces avertissements par défaut. Cet avertissement doit avoir été activé explicitement en passant -Wunused-parameterau compilateur ou implicitement en passant -Wall -Wextra(ou éventuellement une autre combinaison d'indicateurs).

Les avertissements de paramètres inutilisés peuvent simplement être supprimés en passant -Wno-unused-parameterau compilateur, mais notez que cet indicateur de désactivation doit venir après tout indicateur d'activation possible pour cet avertissement dans la ligne de commande du compilateur, afin qu'il puisse prendre effet.


2
Même si ce n'est peut-être pas la meilleure réponse à la question (car la question était de savoir comment éviter l'avertissement, pas comment le désactiver), cette réponse pourrait être les personnes venant de google (comme moi) cherchaient ("comment pour désactiver cet avertissement "). Je donne donc +1, merci pour votre réponse!
mozzbozz

13

moyen sans macro et portable pour déclarer un ou plusieurs paramètres comme inutilisés:

template <typename... Args> inline void unused(Args&&...) {}

int main(int argc, char* argv[])
{
    unused(argc, argv);
    return 0;
}

Très bien, mais notez que cela nécessite C ++ 11 (ou plus récent, bien sûr).
Paul R

J'ai voté contre cette réponse parce que je ne voudrais pas sacrifier le temps de compilation (en utilisant des modèles) juste pour me débarrasser de l'avertissement.
Konrad Kleine

@KonradKleine: Combien de temps de compilation cela pourrait-il éventuellement consommer? En testant sur mon ordinateur, je peux exécuter un millier de ces appels inutilisés () dans un dixième de la seconde.
Daniel McLaury

@DanielMcLaury c'était juste ma supposition et je n'ai fait aucune expérience.
Konrad Kleine

8

L'utilisation de directives de préprocesseur est considérée comme malfaisante la plupart du temps. Idéalement, vous voulez les éviter comme le ravageur. N'oubliez pas qu'il est facile de faire comprendre votre code au compilateur, ce qui permet aux autres programmeurs de comprendre votre code est beaucoup plus difficile. Quelques dizaines de cas comme celui-ci ici et là, il est très difficile à lire pour vous-même plus tard ou pour d'autres en ce moment.

Une façon pourrait être de rassembler vos paramètres dans une sorte de classe d'arguments. Vous pouvez alors utiliser uniquement un sous-ensemble de variables (équivalent à votre affectation réelle de 0) ou avoir différentes spécialisations de cette classe d'arguments pour chaque plate-forme. Cela pourrait cependant ne pas en valoir la peine, vous devez analyser si cela conviendrait.

Si vous pouvez lire des modèles impossibles, vous trouverez peut-être des conseils avancés dans le livre "Exceptional C ++". Si les gens qui liraient votre code pourraient obtenir leur compétence pour englober les trucs fous enseignés dans ce livre, alors vous auriez un beau code qui peut également être facilement lu. Le compilateur serait également bien conscient de ce que vous faites (au lieu de tout cacher en prétraitant)


5
"L'utilisation de directives de préprocesseur est considérée comme la plupart du temps mauvaise." Vraiment? Par qui?
Graeme Perrow

12
Par quiconque se soucie de la portée, de la possibilité de déboguer correctement ou de sa raison.
Projet de loi du

2
@Graeme, il semble innocent lorsque nous n'en voyons que 4 lignes, mais sa propagation provoque des maux de tête. #ifdef vous permet essentiellement de mettre plusieurs versions d'un code source dont le compilateur n'en verra qu'une. Comme Bill le mentionne, cela rend également le débogage plus difficile. J'ai lu sur la perversité des directives du préprocesseur dans divers livres et blogs, et je l'ai moi-même expérimenté. Bien sûr, tout est relatif. Parfois, les directives de préprocesseur ont simplement un sens, car toute autre chose aurait des conséquences pires, et mon point ici est seulement de les éviter autant que possible.
Ben Dadsetan

1
La surutilisation est mauvaise, mais je dirais #define UNUSED(expr) (void)(expr)appropriée.
JonnyJD

7

Tout d'abord, l'avertissement est généré par la définition de variable dans le fichier source et non dans le fichier d'en-tête. L'en-tête peut rester vierge et devrait, car vous pourriez utiliser quelque chose comme doxygen pour générer la documentation de l'API.

Je suppose que vous avez une implémentation complètement différente dans les fichiers source. Dans ces cas, vous pouvez soit commenter le paramètre incriminé, soit simplement écrire le paramètre.

Exemple:

func(int a, int b)
{
    b;
    foo(a);
}

Cela peut sembler cryptique, a donc défini une macro comme UNUSED. Voici comment MFC l'a fait:

#ifdef _DEBUG
#define UNUSED(x)
#else
#define UNUSED(x) x
#endif

Comme cela, vous voyez l'avertissement toujours dans les versions de débogage, peut être utile.


4

N'est-il pas sûr de toujours commenter les noms des paramètres? Si ce n'est pas le cas, vous pouvez faire quelque chose comme

#ifdef _MSC_VER
# define P_(n) n
#else
# define P_(n)
#endif

void ProcessOps::sendToExternalApp(
    QString sAppName, QString sImagePath,
    qreal P_(qrLeft), qreal P_(qrTop), qreal P_(qrWidth), qreal P_(qrHeight))

C'est un peu moins moche.


4
Le fait que le nom du paramètre ne soit pas obligatoire en C ++ - il l'est en C - est juste pour donner un moyen standard et facile d'empêcher l'avertissement.
AProgrammer le

1
@hacker, n'a jamais dit que c'était le cas. J'ai tendance à souligner les différences entre C et C ++, surtout quand elles se trouvent dans des régions que vous pensez être le sous-ensemble commun ... Juste une habitude car je travaille sur une base de code mixte.
AProgrammer le

4

J'ai vu cela au lieu de la (void)param2façon de faire taire l'avertissement:

void foo(int param1, int param2)
{
    std::ignore = param2;
    bar(param1);
}

On dirait que cela a été ajouté en C ++ 11


Il semble faire quelque chose, ne pas être ignoré après la compilation.
GyuHyeon Choi

3

Utiliser un UNREFERENCED_PARAMETER(p)pourrait fonctionner. Je sais qu'il est défini dans WinNT.h pour les systèmes Windows et peut également être facilement défini pour gcc (s'il ne l'a pas déjà).

UNREFERENCED PARAMETER(p) est défini comme

#define UNREFERENCED_PARAMETER(P)          (P)

dans WinNT.h.


2

Utilisez l'indicateur du compilateur, par exemple l'indicateur pour GCC: -Wno-unused-variable


1

Vous pouvez utiliser __unusedpour indiquer au compilateur que la variable peut ne pas être utilisée.

- (void)myMethod:(__unused NSObject *)theObject    
{
    // there will be no warning about `theObject`, because you wrote `__unused`

    __unused int theInt = 0;
    // there will be no warning, but you are still able to use `theInt` in the future
}

2
Quel compilateur? Parce que ce __unusedn'est pas du C ++ standard, et plus précisément, ce que vous avez publié non plus ... C'est Objective-C. Cette réponse n'est donc vraiment utile que pour des compilateurs spécifiques, et elle rend le code non portable, et en fait pas vraiment valide car le code utilisateur n'est pas destiné à utiliser des identificateurs commençant par __, qui sont réservés à l'implémentation.
underscore_d

1

En C ++ 11, voici la solution que j'utilise:

template<typename... Ts> inline void Unreferenced(Ts&&...) {}

int Foo(int bar) 
{
    Unreferenced(bar);
    return 0;
}

int Foo2(int bar1, int bar2) 
{
    Unreferenced(bar1, bar2);
    return 0;
}

Vérifié pour être portable (au moins sur msvc moderne, clang et gcc) et ne pas produire de code supplémentaire lorsque les optimisations sont activées. Sans optimisation, l'appel de fonction supplémentaire est effectué et les références aux paramètres sont copiées dans la pile, mais aucune macro n'est impliquée.

Si le code supplémentaire pose problème, vous pouvez utiliser cette déclaration à la place:

(decltype(Unreferenced(bar1, bar2)))0;

mais à ce stade, une macro offre une meilleure lisibilité:

#define UNREFERENCED(...) { (decltype(Unreferenced(__VA_ARGS__)))0; }

1

Cela fonctionne bien mais nécessite C ++ 11

template <typename ...Args>
void unused(Args&& ...args)
{
  (void)(sizeof...(args));
}

1
Qu'en est-il de cela nécessite C ++ 14 et ne fonctionnerait pas en C ++ 11? Je ne vois rien. De plus, il est déconseillé de l'utiliser ALLCAPSpour autre chose que les macros, ce qui les rend laides et indésirables, mais il n'y a vraiment rien de mal à cela, sauf que ce static_castserait plus agréable.
underscore_d

0

J'ai trouvé que la plupart des réponses présentées ne fonctionnent que pour la variable locale inutilisée et entraîneront une erreur de compilation pour la variable globale statique inutilisée.

Une autre macro devait supprimer l'avertissement de variable globale statique inutilisée.

template <typename T>
const T* UNUSED_VARIABLE(const T& dummy) { 
    return &dummy;
}
#define UNUSED_GLOBAL_VARIABLE(x) namespace {\
    const auto dummy = UNUSED_VARIABLE(x);\
}

static int a = 0;
UNUSED_GLOBAL_VARIABLE(a);

int main ()
{
    int b = 3;
    UNUSED_VARIABLE(b);
    return 0;
}

Cela fonctionne car aucun avertissement ne sera signalé pour la variable globale non statique dans l'espace de noms anonyme.

C ++ 11 est cependant requis

 g++  -Wall -O3  -std=c++11 test.cpp

0

Lol! Je ne pense pas qu'il y ait une autre question sur SO qui révèle tous les hérétiques corrompus par le Chaos mieux que celui-ci!

Avec tout le respect que je dois à C ++ 17, il y a une ligne directrice claire dans C ++ Core Guidelines . AFAIR, en 2009, cette option était disponible ainsi qu'aujourd'hui. Et si quelqu'un dit que c'est considéré comme un bug dans Doxygen, alors il y a un bug dans Doxygen


-14

Je ne vois pas votre problème avec l'avertissement. Documentez dans l'en-tête méthode / fonction que le compilateur xy émettra un avertissement (correct) ici, mais que ces variables sont nécessaires pour la plateforme z.

L'avertissement est correct, pas besoin de le désactiver. Cela n'invalide pas le programme - mais il doit être documenté, qu'il y a une raison.


20
Le problème est que, si vous avez des centaines ou des milliers de ces avertissements, vous risquez de manquer celui qui est utile. (Deux fois, j'étais dans la situation de parcourir plusieurs dizaines de milliers d'avertissements, en éliminant la plupart et en trouvant quelques-uns vraiment utiles une fois qui faisaient allusion à de graves erreurs.) Il est toujours bon de compiler sans avertissements, si possible au niveau d'avertissement le plus élevé.
sbi

4
Dans un projet sur lequel j'ai travaillé l'année dernière, j'ai activé le niveau d'alerte le plus élevé et obtenu environ 10 000 avertissements. Quelques dizaines seulement étaient vraiment utiles. Parmi ceux-ci, une douzaine de bugs vraiment méchants étaient cachés, mais il a fallu plusieurs semaines pour nettoyer la base de code au point où l'on pouvait en voir les quelques plus graves. Si le niveau d'avertissement avait été constamment augmenté et que la base de code avait été maintenue sans avertissement, ces erreurs n'auraient jamais été introduites dans le code.
sbi

1
désolé - mais faire l'analyse de code statique (en utilisant n'importe quel outil dont vous disposez, même si ce n'est que le compilateur) à la fin du projet est un peu comme programmer le programme entier et lorsque vous avez terminé, appuyez sur compiler et espérez que vous n'avez aucune erreur.
Tobias Langner

2
@Richard: J'ai travaillé sur des projets avec des milliers de fichiers sources. Un petit avertissement ici et là, même bien documenté, s'additionne rapidement. Même si vous n'avez que des dizaines d'avertissements qui clignotent pendant une génération (au lieu de centaines ou de milliers), le fait de les rechercher individuellement pour voir s'ils sont nouveaux ou documentés prend trop de temps et, finalement, est gagné. t être fait. Pour cela: Compilez au niveau d'avertissement le plus élevé possible avec zéro avertissement. Chaque avertissement qui apparaît sera immédiatement remarqué, examiné, et soit fixe, soit surpressé.
sbi

2
@sbi: la formation au niveau d'avertissement le plus élevé pour votre compilateur est une forme d'analyse de code statique. L'analyse de code statique consiste simplement à lire le code sans l'exécuter et à en déduire des informations. C'est exactement ce que fait le compilateur lorsqu'il vérifie ses règles pour les avertissements.
Tobias Langner
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.