2010-07-06 8 views
7

D'accord, petite curiosité que j'ai découverte avec mon compilateur C++.C++ applique-t-il des instructions de retour?

J'avais un peu peu de code complexe à refactoriser, et j'ai accidentellement réussi à laisser dans un chemin qui n'avait pas une déclaration de retour. Ma faute. D'un autre côté, cela compilé, et segfaulted quand je l'ai couru et ce chemin a été frappé, évidemment.

Voici ma question: est-ce un bogue de compilateur, ou est-ce qu'il n'y a aucune garantie qu'un compilateur C++ imposera le besoin d'une déclaration de retour dans une fonction de retour non-vide?

Oh, et pour être clair, dans ce cas, c'était une instruction if inutile sans accompagnement. Pas de gotos, pas de sorties, pas d'abandons.

+0

Quel compilateur utilisez-vous? – Dennis

+3

Si sur gcc utilisez [-Wreturn-type'] (http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html), éventuellement avec '-Werror ='. –

+0

même chose est arrivé à moi avec gcc 4.4 –

Répondre

11

Personnellement, je pense que cela devrait être une erreur:

int f() { 
} 

int main() { 
    int n = f(); 
    return 0; 
} 

, mais la plupart des compilateurs traitent comme un avertissement, et vous pouvez même avoir à utiliser des commutateurs de compilateur pour obtenir cet avertissement.Par exemple, sur g ++ dont vous avez besoin pour obtenir -Wall:

[[email protected] NeilB]$ g++ -Wall nr.cpp 
nr.cpp: In function 'int f()': 
nr.cpp:2: warning: no return statement in function returning non-void 

Bien sûr, avec g ++ vous devez toujours compiler avec au moins -Wall de toute façon.

13

Il n'existe aucune garantie qu'un compilateur C++ l'appliquera. Une fonction C++ pourrait sauter hors de son flux de contrôle par des mécanismes inconnus du compilateur. Context change lorsque C++ est utilisé pour écrire un noyau OS est un exemple de cela. Une exception non interceptée lancée par une fonction appelée (dont le code n'est pas nécessairement disponible pour l'appelant) en est une autre.

Certains autres langages, comme Java, imposent explicitement que, avec les connaissances disponibles au moment de la compilation, tous les chemins renvoient une valeur. En C++, cela n'est pas vrai, comme c'est le cas pour beaucoup d'autres occasions dans le langage, comme si l'accès à un tableau hors de ses limites n'était pas vérifié non plus.

+0

"Une fonction C++ pourrait sauter hors de son flux de contrôle par des mécanismes inconnus du compilateur." - Oui, mais le flux sera repris. Un commutateur de contexte revient après tout. Je ne vois vraiment pas ce que cela a à voir avec les valeurs de retour. Le seul cas où la fonction ne sera pas rétablie est si une exception est levée. –

+0

@Neil pas nécessaire. Un appel à 'exit', par exemple, ne pourra jamais revenir en arrière. –

+1

@Johannes OK, et abort() et terminate(). Mais le compilateur ne peut pas voir que ceux-ci nient la nécessité d'un retour, à moins qu'il ne les traite comme "spéciaux" d'une certaine manière. –

4

Le compilateur n'applique pas cela parce que vous avez des connaissances sur les chemins qui sont pratiquement possibles que le compilateur ne le fait pas. Le compilateur ne connaît généralement que ce fichier particulier, pas d'autres qui peuvent affecter le flux à l'intérieur d'une fonction donnée. Donc, ce n'est pas une erreur.

Dans Visual Studio, cependant, il s'agit d'un avertissement. Et nous devrions faire attention à tous les avertissements .... pas vrai? :)

Modifier: Il semble y avoir une discussion sur le moment où cela pourrait se produire. Voici un exemple modifié mais réel de ma bibliothèque de code personnel;

enum TriBool { Yes, No, Maybe }; 

TriBool GetResult(int input) { 
    if (TestOne(input)) { 
     return Yes; 
    } else if (TestTwo(input)) { 
     return No; 
    } 
} 

Ours avec moi parce que c'est vieux code. A l'origine il y avait un "autre retour peut-être" là-bas. :) Si TestOne et TestTwo sont dans une unité de compilation différente, alors lorsque le compilateur atteint ce code, il ne peut pas dire si TestOne et TestTwo peuvent tous deux renvoyer false pour une entrée donnée. Vous, en tant que programmeur qui a écrit TestOne et TestTwo, savez que si TestOne échoue, alors TestTwo réussira. Peut-être qu'il y a des effets secondaires de ces tests, alors ils doivent être faits. Serait-il préférable de l'écrire sans "else if"? Peut être. Probablement. Mais le fait est que ceci est légal en C++ et le compilateur ne peut pas savoir s'il est possible de quitter sans une instruction return. Il est, je suis d'accord, moche et pas bien codé mais c'est légal et Visual Studio va vous donner un avertissement mais il va compiler. N'oubliez pas que le C++ ne vise pas à vous protéger contre vous-même. Il s'agit de vous permettre de faire ce que votre coeur désire dans les limites de la langue, même si cela inclut vous tirer dans le pied.

+0

Cela n'a aucun sens. Le compilateur doit connaître les chemins possibles pour compiler le code. –

+1

@Neil je pense qu'il a un point. Le compilateur ne sait pas toujours à * heure de compilation *. Comme si vous n'aviez aucune idée quand vous avez posté votre commentaire que je posterais une réponse à cela. Mais maintenant vous savez, et possiblement prendre des précautions pour répondre à tour de rôle ou non. Ou vous êtes totalement surpris, comme le C++ sera, et faire des choses indéfinies :) –

+1

C'est un non-sens à mon humble avis. Le graphe de flux de contrôle d'une fonction donnée est parfaitement connu du compilateur après analyse de son code. Il se peut que certains bords ne soient jamais traversés lors de l'exécution du code (pensez à affirmer), mais le compilateur le traite comme tel et tout ce qu'il provoque n'est qu'une supposition (trop) conservatrice. – jpalecek

Questions connexes