3 votes

optimisations de gcc

J'aimerais savoir si le morceau de code suivant va générer une erreur ou un avertissement lors de la compilation avec n'importe quel type d'optimisations gcc/g++ activées.

int a;
a = func();
if (a == 2) {
    assert(false);
}

Je pense que le code suivant peut générer un avertissement "variable définie mais inutilisée", dans la configuration de la version.

int a;
a = func();
assert(a != 2);

Mais qu'en est-il du code ci-dessus ? (gcc peut supprimer l'instruction if elle-même parce que rien ne sera fait ni dans l'instruction if ni dans le bloc if (dans la version release), et lancer un avertissement "variable inutilisée mais définie" )

edit : ce n'est absolument pas une question concernant la réduction de la taille du code ou de l'exe. Je veux connaître un morceau de code qui réussit dans n'importe quelle configuration de construction.

edit : nous désactivons assert en mode release

4voto

Dietrich Epp Points 72865

D'après mes tests, le code suivant génère un avertissement avec -Wall -Wextra -O2 -DNDEBUG :

int a = func(); // warning: unused variable ‘a’
assert(a != 2);

Mais le code suivant ne le fait pas :

// no warnings
int a;
a = func();
assert(a != 2);

Cependant, vous pouvez toujours supprimer les avertissements concernant les variables inutilisées en les transformant en void .

int a = func();
(void) a; // suppresses "unused variable" warning
assert(a != 2);

Pour autant que je sache, la ligne a = func() est toujours considérée comme une utilisation de la variable a alors que l'initialisation le fait no comptent pour l'utilisation.

Je n'essaierais pas de me prémunir contre l'avenir. possible les avertissements du compilateur au fur et à mesure que les compilateurs évoluent et que leurs diagnostics s'améliorent, étant donné que les couvertures peuvent parfois supprimer accidentellement des avertissements valables.

Comment se définit l'affirmation ?

Les comités de normalisation et les responsables de la mise en œuvre de la norme C ont conçu assert afin qu'il ne génère pas d'avertissements intempestifs. Notez à quel point les transformations en void sont...

  • Sans NDEBUG , la glibc définit assert grosso modo de la manière suivante (sauf avec quelque chose d'autre que abort ) :

    #define assert(expr) ((expr) ? (void) 0 : abort())
  • Con NDEBUG La glibc le définit de cette manière (comme l'exige la norme C) :

    #define assert(expr) ((void) 0)
  • La définition suivante de assert n'est pas conforme, car il ne se développe pas en une expression :

    #define assert(expr) { if (expr) { ... } } // wrong

Les définitions sont également légèrement différentes pour le C++. Vous voyez donc, assert est défini de la bonne manière, de sorte qu'il ne crée pas de fausses alertes du compilateur, et il se comporte vraiment syntaxiquement comme un appel de fonction.

1voto

Jonathan Wakely Points 45593

En général, il n'est pas possible de dire qu'un morceau de code va jamais obtenir des avertissements d'un compilateur, car de nouveaux avertissements pourraient être ajoutés à l'avenir ou des bogues du compilateur pourraient provoquer des avertissements erronés.

Je suis presque sûr que GCC n'émettra pas d'avertissement en cas de if défini avec des accolades, précisément parce que cela peut facilement se produire dans un code valide, comme celui-ci (qui est essentiellement très similaire à votre cas) :

int a = func();
if (a == 2)
{
#ifdef SOME_BUILD_SETTING
    launch_missiles();
#endif
}

Le manuel indique

-Corps vide
Avertir si un corps vide apparaît dans un if , else o do while déclaration. Cet avertissement est également activé par -Wextra .

Qui s'appliquerait pour :

#ifdef SOME_BUILD_OPTION
# define LAUNCH_MISSILES launch_missiles()
#else
# define LAUNCH_MISSILES
#endif
if (a==2)
  LAUNCH_MISSILES;

Puis compilé avec -Wextra sans SOME_BUILD_OPTION définis.

Mais avec les accolades, il n'y a pas d'avertissement, et comme le fait remarquer Dietrich Epp, avec les assert il ne prévient pas parce qu'il ne s'étend pas à rien même avec NDEBUG définis.

Dans votre code a est initialisé et sa valeur est utilisée, il serait donc surprenant qu'il avertisse.

1voto

ams Points 10312

Cela peut poser des problèmes si votre assert est supprimée par le préprocesseur, comme ceci :

#ifdef ENABLE_ASSERT
#define assert (CONDITION) {if (!(CONDITION)) abort ();}
#else
#define assert (CONDITION) /* Nothing */
#endif

Mais si vous le faites correctement, il n'y aura aucun problème :

#define assert (CONDITION) {if ((ENABLE_ASSERT) && !(CONDITION)) abort ();}

Dans ce cas, le compilateur verra toujours que a est utilisé dans CONDITION mais l'optimisera lorsque ENABLE_ASSERT est de zéro. Il est généralement préférable de laisser les optimiseurs du compilateur supprimer du code plutôt que d'utiliser le préprocesseur : cela permet d'éviter les avertissements de ce type, et conduit généralement à un code plus lisible, et le code n'a pas besoin d'être réécrit s'il devient un jour un test d'exécution.

C'est évident, ENABLE_ASSERT doit toujours être définie comme nulle ou non nulle.

0voto

Andrew Points 14301

Les deux blocs de code sont corrects, mais je préférerais :

int a = func();
assert(a != 2);

0voto

Jens Gustedt Points 40410

Comme vous le savez sans doute, la assert est gérée avec la macro NDEBUG . Je pense que quelque chose qui utilise un #ifdef NDEBUG serait plus lisible et aurait le même effet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X