Pourquoi le fait de quitter la fin d'une fonction sans vide sans retourner une valeur ne produit-il pas une erreur de compilation?

depuis que j'ai réalisé il y a de nombreuses années, que cela ne produit pas d'erreur par défaut (en GCC au moins), je me suis toujours demandé pourquoi?

je comprends que vous pouvez émettre des indicateurs de compilateur pour produire un avertissement, mais ne devrait-il pas toujours y avoir une erreur? Pourquoi est-ce logique qu'une fonction non vide ne renvoie pas une valeur pour être valide?

un exemple tel que demandé dans les commentaires:

#include <stdio.h>
int stringSize()
{
}

int main()
{
    char cstring[5];
    printf( "the last char is: %cn", cstring[stringSize()-1] ); 
    return 0;
}

...compiler.

146
demandé sur DeiDei 2009-10-23 01:21:24

8 réponses

Les standards

C99 et C++ n'ont pas besoin de fonctions pour retourner une valeur. Le rapport de retour manquant dans une fonction de retour de valeur sera défini (pour retourner 0 ) seulement dans la fonction main .

le raisonnement inclut que vérifier si chaque chemin de code renvoie une valeur est assez difficile, et une valeur de retour pourrait être définie avec assembleur intégré ou d'autres méthodes délicates.

à Partir de C++11 projet de:

§ 6.6.3 /2

S'écoulant de la fin d'une fonction [...] résulte en un comportement non défini dans une fonction de retour de valeur.

§ 3.6.1 /5

si le contrôle atteint la fin de main sans rencontrer une déclaration return , l'effet est celui de l'exécution

return 0;

noter que le comportement décrit dans C++ 6.6.3 / 2 n'est pas le même en C.


gcc vous donnera un avertissement si vous l'appelez avec l'option de type-Wreturn.

- Wreturn-type avertir chaque fois qu'une fonction est définie avec un retour-type qui par défaut à int. Aussi mettre en garde tout instruction de retour sans retourner de valeur dans une fonction dont le retour n'est pas void (tomber de la fin de la corps de la fonction est considérée comme retourner sans valeur), et sur un retour déclaration avec une expression dans un fonction dont le type de retour est nul.

cet avertissement est activé par - MUR .


tout comme une curiosité, regardez ce que ce code fait:

#include <iostream>

int foo() {
   int a = 5;
   int b = a + 1;
}

int main() { std::cout << foo() << std::endl; } // may print 6

ce code a un comportement formellement Non défini, et dans la pratique c'est appelant la convention et architecture dépendante. Sur un système particulier, avec un compilateur particulier, la valeur de retour est le résultat de la dernière évaluation de l'expression, stockée dans le registre eax du processeur de ce système.

140
répondu fnieto - Fernando Nieto 2017-05-23 11:54:36

gcc ne vérifie pas par défaut que tous les chemins de code renvoient une valeur parce qu'en général cela ne peut pas être fait. Il suppose que vous savez ce que vous faites. Prenons un exemple courant d'énumération:

Color getColor(Suit suit) {
    switch (suit) {
        case HEARTS: case DIAMONDS: return RED;
        case SPADES: case CLUBS:    return BLACK;
    }

    // Error, no return?
}

vous le programmeur savez que, sauf un bug, cette méthode renvoie toujours une couleur. gcc croit que vous savez ce que vous faites de sorte qu'il ne vous force pas à mettre un retour au bas de la fonction.

javac, d'un autre côté, essaie de vérifier que tous les chemins de code retournent une valeur et envoie une erreur si elle ne peut pas prouver qu'ils le font tous. Cette erreur est mandatée par la spécification Java language. Notez que parfois, il est faux et vous devez mettre dans une déclaration de retour inutile.

char getChoice() {
    int ch = read();

    if (ch == -1 || ch == 'q') {
        System.exit(0);
    }
    else {
        return (char) ch;
    }

    // Cannot reach here, but still an error.
}

C'est une différence philosophique. C et c++ sont des langages plus permissifs et de confiance que Java ou C# et donc certaines erreurs dans les nouveaux langages sont des avertissements en C/C++ et certains avertissements sont ignorés ou désactivé par défaut.

41
répondu John Kugelman 2009-10-22 22:18:29

vous voulez dire, pourquoi sortir de la fin d'une fonction de retour de valeur (i.e. sortir sans un return explicite ) n'est pas une erreur?

tout d'abord, en C si une fonction renvoie quelque chose de significatif ou non n'est critique que lorsque le code d'exécution réellement utilise la valeur renvoyée. Peut-être que le langage ne voulait pas vous forcer à rendre quoi que ce soit quand vous savez que vous n'allez pas l'utiliser de toute façon la plupart du temps.

Deuxièmement, apparemment la spécification du langage ne voulait pas forcer les auteurs du compilateur à détecter et vérifier toutes les voies de contrôle possibles pour la présence d'un return explicite (bien que dans de nombreux cas ce n'est pas si difficile à faire). En outre, certains chemins de contrôle peuvent conduire à des "non-returning functions - le trait qui est généralement non connu du compilateur. De tels chemins peuvent devenir une source de faux positifs gênants.

Note aussi, que C et c++ diffèrent dans leurs définitions du comportement dans ce cas. En C++, la fin d'une fonction de retour de valeur est toujours un comportement non défini (indépendamment du fait que le résultat de la fonction soit utilisé ou non par le code appelant). Dans C cela provoque un comportement non défini seulement si le code appelant essaye d'utiliser la valeur retournée.

13
répondu AnT 2016-09-23 18:41:39

il est légal en C/C++ de ne pas revenir d'une fonction qui prétend retourner quelque chose. Il existe un certain nombre de cas d'utilisation, tels que l'appel exit(-1) , ou une fonction qui l'appelle ou lance une exception.

le compilateur ne va pas rejeter legal C++ même s'il conduit à UB si vous lui demandez de ne pas le faire. En particulier, vous demandez que no warnings soit généré. (Gcc tourne encore sur certains par défaut, mais quand ils sont ajoutés ceux semblent pour s'harmoniser avec les nouvelles fonctionnalités ne sont pas nouvelles mises en garde pour les anciennes fonctionnalités)

changer le no-arg gcc par défaut pour émettre des avertissements pourrait être un changement de rupture pour les scripts existants ou les systèmes make. Ceux bien conçus soit -Wall et traitent des avertissements, ou basculer des avertissements individuels.

apprendre à utiliser une chaîne d'outils C++ est un obstacle pour apprendre à être un programmeur C++, mais les chaînes d'outils C++ sont généralement écrites par et pour des experts.

4
répondu Yakk - Adam Nevraumont 2016-05-28 20:30:18

dans quelles circonstances ne produit-il pas une erreur? Si elle déclare un type de retour et ne renvoie pas quelque chose, cela ressemble à une erreur pour moi.

la seule exception à laquelle je peux penser est la fonction main() , qui n'a pas besoin du tout d'une instruction return (au moins en C++; Je n'ai aucun des standards C sous la main). S'il n'y a pas de déclaration, elle agira comme si return 0; était le dernier énoncé.

0
répondu David Thornley 2009-10-22 21:25:37

sonne comme vous avez besoin de monter vos avertissements de compilateur:

$ gcc -Wall -Wextra -Werror -x c -
int main(void) { return; }
cc1: warnings being treated as errors
<stdin>: In function ‘main’:
<stdin>:1: warning: ‘return’ with no value, in function returning non-void
<stdin>:1: warning: control reaches end of non-void function
$
0
répondu Chris Lutz 2009-10-22 21:28:11

je crois que c'est à cause du code d'héritage (c n'a jamais exigé l'instruction return donc C++). Il y a probablement une énorme base de code qui dépend de cette "fonctionnalité". Mais au moins il y a -Werror=return-type pavillon sur de nombreux compilateurs (y compris gcc et clang).

0
répondu d.lozinski 2015-04-16 18:11:18

C'est une violation de contrainte en c99, mais pas en c89. Contraste:

c89:

3.6.6.4 la return déclaration

contraintes

A return la mention comportant une expression ne doit pas figurer dans un fonction dont le type de retour est void .

c99:

6.8.6.4 le return déclaration

contraintes

a return une instruction avec une expression ne doit pas apparaître dans une fonction dont le type de retour est void . Une instruction return sans expression ne doit apparaître que dans une fonction dont le type de retour est void .

même en mode --std=c99 , gcc ne lancera qu'un avertissement (bien que sans avoir besoin d'activer des drapeaux supplémentaires -W )., tel que requis par défaut ou dans c89/90).

Éditer pour ajouter que dans c89, "atteindre le } qui termine une fonction est équivalent à l'exécution d'une return déclaration sans expression" (3.6.6.4). Cependant, en c99, le comportement n'est pas défini (6.9.1).

-2
répondu Matt B. 2009-10-22 21:51:41