C: comparaison avec NULL

Arguments religieux mis à part:

  • Option1:

    if (pointer[i] == NULL) ...
    
  • Option2:

    if (!pointer[i]) ...  
    

En C, l'option1 est-elle fonctionnellement équivalente à l'option2?

La résolution ultérieure est-elle plus rapide en raison de l'absence de comparaison ?

21
demandé sur Ande TURNER 2009-08-16 15:09:41

11 réponses

J'aime le second, les autres aiment le premier.

En fait, je préfère un troisième type au premier:

if (NULL == ptr) {
   ...
}

Parce que alors je:

  • ne sera pas en mesure de manquer et tapez simplement un " = "
  • ne manquera pas le "= = NULL " et le confondra avec le contraire si la condition est longue (plusieurs lignes)

Fonctionnellement, ils sont équivalents.

Même si un pointeur NULL n'est pas " 0 " (tous les bits zéro), if (!ptr) se compare au pointeur NULL.

Le ce qui suit est incorrect. Il est toujours là parce qu'il y a beaucoup de commentaires qui s'y réfèrent: Cependant, ne comparez pas un pointeur avec un zéro littéral. Cela fonctionnera presque partout mais est un comportement indéfini IIRC.

15
répondu Thomas 2014-07-19 08:44:11

Je préfère le style explicite (première version). Il est évident qu'il y a un pointeur impliqué et non un entier ou autre chose, mais c'est juste une question de style.

Du point de vue de la performance, cela ne devrait pas faire de différence.

33
répondu Laserallan 2009-08-16 11:17:44

Équivalent. Il le dit dans la norme de langue. Et les gens ont les plus damndest préférences religieuses!

29
répondu Norman Ramsey 2009-08-16 21:20:34

Il est souvent utile de supposer que les auteurs de compilateurs ont au moins un minimum d'intelligence. Votre compilateur est Pas écrit par des canetons commotionnés. Il est écrit par des êtres humains, avec des années d'expérience en programmation et des années passées à étudier la théorie du compilateur. Cela ne signifie pas que votre compilateur est parfait, et sait toujours mieux, mais celasignifie qu'il est parfaitement capable de gérer des optimisations automatiques triviales.

Si les deux formes sont équivalentes, alors pourquoi le compilateur ne traduirait-il pas simplement l'un dans l'autre pour s'assurer que les deux sont également efficaces?

Si {[0] } était plus lent que if (!pointer[i]), le compilateur ne le changerait-il pas simplement en une deuxième forme plus efficace?

Donc non, en supposant qu'ils sont équivalents, ils sont tout aussi efficaces.

Quant à la première partie de la question, oui, ils sont équivalents. La norme de langage l'indique explicitement quelque part-un pointeur évalue à true s'il est non NULL, et false s'il l'est NULL, donc les deux sont exactement identiques.

19
répondu jalf 2009-08-16 13:47:28

Presque certainement pas de différence de performance. Je préfère le style implicite de la seconde, cependant.

9
répondu Barry Kelly 2009-08-16 11:14:04

NULL doit être déclaré dans l'un des fichiers d'en-tête standard en tant que tel:

#define NULL ((void*)0)

Donc, de toute façon, vous comparez contre zéro, et le compilateur devrait optimiser les deux de la même manière. Chaque processeur a une "optimisation" ou un opcode pour comparer avec zéro.

3
répondu Mark Rushakoff 2009-08-16 11:24:53

L'optimisation précoce est mauvaise. La micro-optimisation est également mauvaise, sauf si vous essayez de presser chaque dernier bit De Hz de votre CPU, il ne sert à rien de le faire. Comme les gens l'ont déjà montré, le compilateur optimisera la plupart de votre code de toute façon.

Il est préférable de rendre votre code aussi concis et lisible que possible. Si c'est plus lisible

if (!ptr)

Que ce

if (NULL==ptr)

Ensuite, utilisez-le. Tant que tous ceux qui liront votre code sont d'accord.

Personnellement, j'utilise la valeur entièrement définie (NULL= = ptr) donc il est clair ce que je vérifie. Peut être plus long à taper, mais je peux facilement lire. Je pense à la !ptr serait facile à manquer ! si la lecture rapidement.

1
répondu shimpossible 2009-08-16 20:16:38

Cela dépend vraiment du compilateur. Je serais surpris si la plupart des compilateurs C modernes ne généraient pas de code pratiquement identique pour le scénario spécifique que vous décrivez.

Obtenir votre compilateur pour générer une assemblée d'inscription pour chacun de ces scénarios et vous pouvez répondre à votre propre question (pour votre compilateur :)).

Et même si elles sont différentes, la différence de performance sera probablement hors de propos dans les applications pratiques.

0
répondu 2009-08-16 11:15:18

Activez l'optimisation du compilateur et ils sont fondamentalement les mêmes

Testé sur gcc 4.3.3

int main (int argc, char** argv) {
   char c = getchar();
   int x = (c == 'x');
   if(x == NULL)
      putchar('y');
   return 0;
}

Vs

int main (int argc, char** argv) {
   char c = getchar();
   int x = (c == 'x');
   if(!x)
      putchar('y');
   return 0;
}


gcc -O -o test1 test1.c
gcc -O -o test2 test2.c


diff test1 test2

Produit aucune sortie :)

0
répondu Charles Ma 2009-08-16 11:39:33

J'ai fait un vidage d'assemblage, et j'ai trouvé la différence entre les deux versions:

@@ -11,8 +11,7 @@
pushl %ecx
subl $20, %esp
movzbl -9(%ebp), %eax
- movsbl %al,%eax
- testl %eax, %eax
+ testb %al, %al

Il semble que ce dernier génère réellement une instruction et la première en génère deux, mais c'est assez non scientifique.

C'est gcc, pas d'optimisations:

Essai1.c:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{ 
  char *pointer[5];

if(pointer[0] == NULL) {
  exit(1);
}

exit(0);

}

Test2.c: Changer pointer[0] == NULL en !pointer[0]

Gcc-s test1.c, gcc - s test2.C, test diff-U1.s essai2.s

-1
répondu ctennis 2009-08-16 11:42:41
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{   
  char pointer[5];  
  /* This is insense you are comparing a pointer to a value */   
  if(pointer[0] == NULL) {     
    exit(1);
  } 
  ...
}

=>           ...    
  movzbl    9(%ebp), %eax  # your code compares a 1 byte value to a signed 4 bytes one 
  movsbl    %al,%eax        # Will result in sign extension...
  testl  %eax, %eax      
              ...

Attention, gcc aurait dû sortir un avertissement, sinon la compilation de cas avec -Wall drapeau sur Cependant, vous devez toujours compiler en code gcc optimisé. BTW, précédez votre variable avec le mot-clé volatile afin d'éviter que gcc ne l'ignore...

Mentionnez toujours la version de construction de votre compilateur:)

-1
répondu ZeroCool 2009-08-17 02:39:54