2010-12-01 29 views
10

J'ai récemment trébuché à travers le comportement suivant du programme alternatif d'écriture gcc 3.2.2:Pourquoi un « nom de la fonction » évaluée à true C et comment être averti sur ce

Dans une instruction if j'ai oublié les accolades d'une fonction et a écrit:

if(myFunc)... au lieu de if(myFunc())...

Cela ne génère pas une erreur ni un avertissement bien que j'ai à peu près tous les avertissement allumé. Il a simplement été évalué à true. Pourquoi ce code légal écrit-il en premier lieu? Parce que la fonction existe/a une adresse? Est-ce que quelqu'un sait comment on pourrait éviter de telles erreurs ou s'il y a une option d'avertissement que j'ai oubliée? Ce problème est-il mieux résolu dans les versions ultérieures de gcc?

Voici l'appel exact du compilateur complet:

msp430-gcc -g -Os -mmcu=msp430x1611 -Wall -W -Wfloat-equal -Wundef -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wwrite-strings -Wsign-compare -Waggregate-return -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations 
-Wredundant-decls -Wnested-externs -Wimplicit-function-declaration -Werror 

(Depuis que je suis obligé d'utiliser gcc 3.2.3 il n'y a pas -Wextra)

+2

Tant que 'myFunc' est défini, true true et la branche toujours prise, on s'attendrait à ce qu'il y ait du code mort s'il y a une branche' else'. Cela pourrait déclencher un avertissement ... Aussi mon 'man gcc' dit *" -Wextra (Cette option était appelée -W. L'ancien nom est toujours supporté, mais le nouveau nom est plus descriptif.) "* – dmckee

+0

Est' myFunc 'une fonction ou un pointeur de fonction? –

+0

@Adam: myFunc() est une fonction ordinaire – Martin

Répondre

16

if (myFunc) est équivalent à if (&myFunc), de sorte que vous » re tester l'adresse d'une fonction, qui bien sûr sera toujours non nulle, c'est-à-dire vraie.

avec gcc 4.2.1 et -Wall je reçois l'avertissement suivant:

myfunc.c:11: warning: the address of ‘myFunc’ will always evaluate as ‘true’

+0

Je craignais sth. comme ça. Une idée de comment être averti avec des versions plus anciennes de gcc (3.2.2)? – Martin

+0

@Martin: tout ce que je peux suggérer est d'utiliser une version plus récente de gcc –

+0

Est-ce que ANSI C déclare qu'il sera toujours non nul? (Unlikely/= always.) –

3

myFunc est simplement l'adresse mémoire de la fonction, et est non nul.

Votre instruction if est à peu près le même que l'écriture:

if (0x08451234) { ... } 

Et comme une valeur non nulle, il est true.

Aucun avertissement ne semble approprié, car il est valide et même assez commun de tester les pointeurs de fonction pour voir s'ils sont NULL ou non.

+2

Il est courant de tester la fonction * pointeurs *. Il n'est pas courant de tester * fonctions *, qui ont toujours une adresse différente de zéro. –

+0

Je ne suis pas sûr qu'il y ait une grande différence dans le code compilé entre un pointeur de fonction et une fonction. Ils sont tous les deux juste des adresses qui peuvent être jmp'd. – abelenky

+1

abelenky: Il y a. L'un est un emplacement de mémoire qui contient l'adresse de la fonction (et peut être réaffecté), tandis que l'autre est simplement l'adresse littérale. –

0

Les pointeurs vers des fonctions sont parfois utiles - comme des rappels, par exemple dans des routines de tri ou de capture de données. Ou pour faire des routines de type calculées-goto optimisées, car C n'a pas de modèles.

Mais 99% du temps, il est une erreur, de nouveaux compilateurs vous avertir

1

myFunc, depuis son nom d'une fonction sera toujours évaluée à true parce que son pointeur. Plus précisément, il a pour être un pointeur non nul, car vous aurez besoin de le déréférencer. Un pointeur null évaluerait à false. En bref, il ne semble pas y avoir de moyen pour le compilateur de vous dire que vous avez fait une erreur. Ce que vous devez faire est d'avoir des tests unitaires qui invoquent séparément les réponses true et false afin que vous puissiez dire que vous avez appelé la fonction.

0

Cela doit prendre en charge un ancien hack de l'éditeur de liens; De nombreux compilateurs/lieurs (y compris les binutils gcc et GNU) vous permettent de définir un symbole faible pour une fonction évaluée à 0, sauf si un autre fichier objet/bibliothèque partagée qui a été lié remplace la valeur du symbole. glibc utilise cette astuce pour certains hacks de compatibilité de version.

+0

Est-ce vraiment pourquoi il n'y a pas d'avertissement? – SamB