Question

Dans plusieurs langages de programmation modernes (y compris C ++, Java et C #), le langage permet le débordement d'entier se produire au moment de l'exécution sans générer aucune sorte de condition d'erreur.

Par exemple, considérons cette méthode (artificielle) C #, qui ne prend pas en compte la possibilité de débordement / dépassement de capacité. (Par souci de brièveté, la méthode ne gère pas non plus le cas où la liste spécifiée est une référence null.)

//Returns the sum of the values in the specified list.
private static int sumList(List<int> list)
{
    int sum = 0;
    foreach (int listItem in list)
    {
        sum += listItem;
    }
    return sum;
}

Si cette méthode est appelée comme suit:

List<int> list = new List<int>();
list.Add(2000000000);
list.Add(2000000000);
int sum = sumList(list);

Un dépassement de capacité se produira dans la méthode sumList () (car le type int en C # est un entier signé de 32 bits et la somme des valeurs dans le la liste dépasse la valeur de l’entier signé maximum sur 32 bits). La variable somme aura une valeur de -294967296 (pas une valeur de 4000000000); ce n'est probablement pas ce que le développeur (hypothétique) de la méthode sumList avait prévu.

Évidemment, les développeurs peuvent utiliser diverses techniques pour éviter le débordement d’entier, par exemple en utilisant un type tel que celui de Java. BigInteger , ou le vérifié mot clé et / vérifié commutateur de compilateur en C #.

Cependant, la question qui m'intéresse est de savoir pourquoi ces langages ont été conçus pour permettre par défaut aux dépassements d'entier de se produire, au lieu, par exemple, de déclencher une exception lorsqu'une opération exécutée à l'exécution est effectuée. entraîner un débordement. Il semble qu'un tel comportement permettrait d'éviter les bogues dans les cas où un développeur néglige de prendre en compte le risque de débordement lors de l'écriture de code exécutant une opération arithmétique pouvant entraîner un débordement. (Ces langages auraient pu inclure quelque chose comme un mot clé "non vérifié" qui pourrait désigner un bloc dans lequel le dépassement d’entier est autorisé sans exception, dans les cas où ce comportement est explicitement prévu par le développeur; C # effectivement possède-t-il ?)

La réponse se résume-t-elle simplement à des performances: les concepteurs de langages ne voulaient pas que leurs langues respectives aient l'option " slow " Opérations entières arithmétiques où l'exécution doit faire un travail supplémentaire pour vérifier si un dépassement de capacité s'est produit, sur chaque opération arithmétique applicable - et cette considération de performances l'emporte sur la valeur d'éviter "silence". échecs en cas de débordement par inadvertance?

Existe-t-il d'autres raisons pour cette décision de conception de langage, outre les considérations de performances?

Était-ce utile?

La solution

En C #, c’était une question de performance. Plus précisément, l'analyse comparative «out-of-box».

Quand C # était nouveau, Microsoft espérait que beaucoup de développeurs C ++ le passeraient. Ils savaient que beaucoup de gens du C ++ pensaient que le C ++ était rapide, en particulier plus rapide que les langages qui "gaspillent". temps sur la gestion automatique de la mémoire et autres.

Les adoptants potentiels et les réviseurs de magazines obtiendront probablement une copie du nouveau C #, l'installeront, créeront une application triviale que personne ne pourrait jamais écrire dans le monde réel, l'exécutera dans une boucle serrée et mesurera sa durée. a pris. Ensuite, ils prenaient une décision pour leur entreprise ou publiaient un article basé sur ce résultat.

Le fait que leur test ait montré que C # était plus lent que le C ++ nativement compilé est le genre de chose qui découragerait rapidement les gens de C #. Le fait que votre application C # attrape automatiquement les débordements / débordements est le genre de choses qu'il pourrait manquer. Donc, il est désactivé par défaut.

Je pense qu'il est évident que 99% du temps que nous voulons / vérifions d'être sur. C'est un compromis malheureux.

Autres conseils

Je pense que la performance est une très bonne raison. Si vous considérez chaque instruction dans un programme typique qui incrémente un entier, et si au lieu de l'opération simple d'ajouter 1, il devait vérifier chaque fois si l'ajout de 1 déborderait le type, le coût en cycles supplémentaires serait plutôt sévère.

Vous travaillez en supposant que le dépassement d'entier est toujours un comportement indésirable.

Parfois, le dépassement d'entier est le comportement souhaité. Un exemple que j'ai vu est la représentation d'une valeur de titre absolue sous forme de nombre à virgule fixe. Avec un unsigned int, 0 est 0 ou 360 degrés et le nombre entier non signé maximum de 32 bits (0xffffffff) est la plus grande valeur juste en dessous de 360 ??degrés.

int main()
{
    uint32_t shipsHeadingInDegrees= 0;

    // Rotate by a bunch of degrees
    shipsHeadingInDegrees += 0x80000000; // 180 degrees
    shipsHeadingInDegrees += 0x80000000; // another 180 degrees, overflows 
    shipsHeadingInDegrees += 0x80000000; // another 180 degrees

    // Ships heading now will be 180 degrees
    cout << "Ships Heading Is" << (double(shipsHeadingInDegrees) / double(0xffffffff)) * 360.0 << std::endl;

}

Il existe probablement d'autres situations dans lesquelles le dépassement est acceptable, comme dans cet exemple.

C / C ++ n’impose jamais le comportement du piège. Même la division évidente par 0 est un comportement indéfini en C ++, pas un type d'interruption spécifié.

Le langage C n’a aucune notion de piégeage, à moins que vous ne comptiez les signaux.

C ++ a pour principe de conception de ne pas introduire de temps système qui n’est pas présent en C à moins que vous ne le demandiez. Stroustrup n’aurait donc pas voulu imposer que les entiers se comportent de manière à ne nécessiter aucune vérification explicite.

Certains premiers compilateurs, ainsi que des implémentations légères pour du matériel restreint, ne prennent pas du tout en charge les exceptions, et les exceptions peuvent souvent être désactivées avec les options du compilateur. Exiger des exceptions pour les langues intégrées serait problématique.

Même si C ++ avait vérifié les entiers vérifiés, 99% des programmeurs des premiers temps se seraient éteints s'ils étaient désactivés pour améliorer les performances ...

Parce que la vérification du débordement prend du temps. Chaque opération mathématique primitive, qui se traduit normalement par une seule instruction d'assemblage, doit inclure une vérification du débordement, ce qui entraîne plusieurs instructions d'assemblage, ce qui peut entraîner un programme plusieurs fois plus lent.

Il s'agit probablement d'une performance de 99%. Sur x86, il faudrait vérifier l’indicateur de débordement à chaque opération, ce qui serait un énorme succès.

Les 1% restants couvriraient les cas dans lesquels des personnes manipulent des bits avec fantaisie ou sont "imprécises" dans le mélange d'opérations signées et non signées et veulent la sémantique de débordement.

La compatibilité ascendante est un problème majeur. Avec C, on supposait que vous accordiez suffisamment d’attention à la taille de vos types de données pour qu’en cas de débordement ou de dépassement excessif, c’était ce que vous souhaitiez. Ensuite, avec C ++, C # et Java, très peu de choses ont changé avec la façon dont le "intégré" types de données travaillés.

Ma compréhension de la raison pour laquelle les erreurs ne seraient pas générées par défaut au moment de l’exécution se résume à la volonté de créer des langages de programmation ayant un comportement de type ACID. Plus précisément, le principe selon lequel tout ce que vous le codez doit faire (ou ne pas coder) le fera (ou ne le fera pas). Si vous n'avez pas codé de gestionnaire d'erreur, la machine "supposera" en vertu de l'absence de gestionnaire d'erreur, que vous voulez vraiment faire la chose ridicule, sujette aux accidents que vous lui dites de faire.

(référence ACID: http://en.wikipedia.org/wiki/ACID )

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top