-1
votes

Étrangers entiers en c langage

J'ai le code:

1839551928
-2135227064
41523672
// And more strange numbers


5 commentaires

Qu'en est-il du fait que vous définissez int somme (int A, int b, int c) mais l'appelez comme somme (1, 3) ( ( avec moins d'arguments que de paramètres)? Est-ce intentionnel?


(1) rien (2) ce n'est pas le cas, c'est pourquoi tout se brise. Permis pour des raisons historiques. Mais votre compilateur vous a probablement crié à vous, que vous devez faire attention à C et traiter comme une erreur.


Voir comportement non défini


J'ai lu que si le compilateur ne connaît pas la signature de la fonction, il ne peut pas générer des erreurs, c'est pourquoi je voulais voir ce qui se passera avec des paramètres manqués.


Je viens de compiler votre programme avec GCC 6.3.0 et j'ai obtenu un avertissement: "AVERTISSEMENT: Déclaration implicite de la fonction" SUME "[-WIMPLICIT-FONCTION-DÉCLARATION]". Vous auriez dû obtenir le même avertissement et si vous l'avez obtenu, vous auriez dû le citer dans votre question.


5 Réponses :


1
votes

Ceci est comportement non défini par 6.5.2.2 Appels de fonction , paragraphe 9 de la norme C :

Si la fonction est définie avec un type qui n'est pas compatible avec le type (de l'expression) pointé par l'expression qui indique la fonction appelée, le comportement est indéfini.

Fonctions sans prototypes sont autorisés sous 6.5. 2.2 Appels de fonctions , paragraphe 6 :

Si l'expression qui dénote la fonction appelée a un type qui n'inclut pas un prototype, les promotions entier sont effectuées sur chaque argument et des arguments qui ont un float de type sont favorisés. Celles-ci s'appellent les promotions d'argument par défaut. Si le nombre d'arguments ne correspond pas au nombre de paramètres, le comportement n'est pas défini. ...

Remarque à nouveau: si les paramètres passés ne correspondent pas aux arguments attendus, le comportement est indéfini.


4 commentaires

@CoffeffeetAbableSpresso bien, merci. Je viens de citer la norme. Vous avez expliqué mieux ce qui se passe. Cela peut vous procurer des bowvotes de certaines affiches ici quand un comportement indéfini est en cours de discussion - c'est ce qui a probablement obtenu le bidonvote actuel: "Bah, ce n'est que des comportements indéfinis et non dignes d'enquête ou de raisonnement!" Bien sûr, ce n'est pas très utile pour quiconque nouveau pour C qui ne comprend pas quel est le comportement indéfini.


Votre réponse est correcte pour C90, mais incorrecte pour C99 et plus tard. Ce n'est pas simplement un comportement indéfini. À partir de C99 ou ultérieure, l'appel somme (1, 3) est une violation de contrainte, car la règle "implicite int " a été supprimée. Un message de diagnostic est requis. (Qui peut être un avertissement non mortel - qui est malheureux malheureux.) Il est toujours légal d'appeler une fonction sans un prototype de visible , mais il n'est pas invalide d'appeler une fonction sans explicitement , comme le fait le programme de l'OP. Voir ma réponse.


@Keiththompson si c'est une violation de contrainte (et 6.5.2.2P2 m'a presque fait publier que le code est une violation de contrainte ...), qui n'explique pas la libellation telle que "pour un appel à une fonction sans prototype de fonction sans traitement de la portée où la fonction n'est pas définie avec un prototype de fonction "dans J.2 Comportement non défini . Ce libellé est au mieux incompatible avec un manque de prototype étant une violation de contraintes. Il y a une série de définitions UB similaires à celle-là. Une violation de contrainte n'aurait pas besoin de définir comme UB, serait-ce?


Un prototype est une déclaration de fonction qui spécifie les types des paramètres. Appeler une fonction sans visible Déclaration est autorisée dans le C90, mais est une violation de contrainte en C99 et plus tard. Appeler une fonction sans visible prototype est valable dans toutes les versions de C, mais une déclaration est toujours requise en C99 et plus tard.



1
votes

dans strictement standard conformaire C, si vous ne déclarez pas une fonction avant de l'utiliser, il assumera certains types d'arguments par défaut pour la fonction.C'est basé sur des versions précoces de C avec un système de type plus faible et retenu uniquement pour rétrocompatibilité. Il ne doit pas être utilisé de manière générale. Je vais ignorer les détails ici, mais dans votre cas, il suppose que la somme prend 2 intens et retourne un int.

Appeler une fonction avec le mauvais nombre de paramètres, comme vous le faites ici, est un comportement indéfini. Lorsque vous appelez somme, le compilateur pense qu'il faut deux entiers, il y a donc deux entiers. Cependant, lorsque la fonction est réellement appelée, il essaie de lire un autre entier, C . Puisque vous n'avez passé que 2 INTS, l'espace pour C contient une merde aléatoire, ce qui est ce que vous voyez lorsque vous imprimez. Notez que cela n'a pas à faire cela, car il s'agit d'un comportement indéfini, cela pourrait faire n'importe quoi. Cela aurait pu donner des valeurs pour B & C, par exemple.

Évidemment, ce comportement est confus, et vous ne devez pas compter sur un comportement non défini, vous seriez donc mieux en train de compiler avec des paramètres de compilateur plus stricts afin que ce programme ne compilait pas. (La version appropriée déclarerait la somme supérieure principale.)


4 commentaires

Il va supposer que la fonction prend des entiers pas vraiment. Ce n'est pas aussi simple. L'argument subira des promotions d'argumentation par défaut.


Vous avez raison, j'essayais de simplifier mais dans ce cas, j'ai simplifié le but d'être faux. Je vais éditerai.


@ indéfinle7887 J'ai suscité, je pensais que c'était une question valable


Dans la norme C depuis la norme de 1999, appeler une fonction sans déclaration visible est la violation de la contrainte (le C plus proche de dire "illégal"). L'argument par défaut et les hypothèses de type de retour appliquées uniquement dans la version de 1990 de la langue. De nombreux compilateurs mettent toujours en œuvre la sémantique plus ancienne pour la compatibilité arriérée.



0
votes

1) Puisque vous n'avez pas fourni de valeur pour le paramètre "C" lors de l'appel de la fonction "somme", sa valeur à l'intérieur de la fonction est indéfinie. Si vous avez déclaré la fonction avant MAIN, votre programme ne compilerait même pas, et vous obtiendrez «Erreur: trop peu d'arguments pour fonctionner appelez» Erreur.

2) Normalement, ce n'est pas le cas. La fonction doit être déclarée avant l'appel afin que le compilateur puisse vérifier la signature de la fonction. Les optimisations du compilateur ont résolu ceci pour vous dans ce cas.


1 commentaires

Depuis que vous n'avez pas fourni de valeur pour le paramètre "C" lors de l'appel de la fonction "somme", sa valeur à l'intérieur de la fonction est indéfinie. pas nécessairement. En fonction de la convention de passage de l'argument pour la plate-forme, A pourrait très bien être le paramètre sans valeur attribuée. Ou quelque chose d'autre - c'est un comportement indéfini et il n'est pas vraiment possible de le caractériser, en particulier avec l'optimisation des compilateurs.



0
votes

Je ne suis pas sûr à 100% si c fonctionne exactement comme ceci, mais votre fonction appelle de fonctionner comme une pile en mémoire. Lorsque vous appelez une fonction, vos arguments sont mis sur cette pile afin que, dans la finition, vous pouvez y accéder en sélectionnant moins de positions x sur la mémoire. Donc: Vous appelez somm (1, 3) La pile aura 1 et le haut a 3. Lors de l'exécution de la foulée, la dernière position de la mémoire pour l'argument de 1º (il récupère le 1), puis la position avant celle-ci pour l'argument de 2º (récupération de la 3), il existe un argument de 3º afin qu'il accède à la position. avant cela aussi. Ce poste est Garbige comme non mis par vous et différent chaque fois que vous l'exécutez.

J'espère que c'était clair. Remetber que la pile fonctionne est inversée afin que chaque fois que vous ajoutez quelque chose, il va à la position de la mémoire précédente, pas la suivante.


1 commentaires

Ce n'est pas comment c fonctionne. Tout d'abord, il a invoqué un comportement non défini afin que tout puisse arriver, et deuxièmement, les compilateurs modernes passent généralement les 4 premiers arguments d'une fonction dans des registres.



3
votes

Je suppose que le code de votre question est le code que vous compilez et exécutant réellement: xxx

l'appel à printf n'est pas valide, car Vous n'avez pas le #include requis . Mais ce n'est pas ce que vous demandez, alors nous l'ignorerons. La question a été modifiée pour ajouter la directive Inclure.

dans la norme C, puisque la norme de 1999, appelant une fonction ( somme dans ce cas) avec Aucune déclaration visible n'est une violation de contraintes . Cela signifie qu'un diagnostic est requis (mais un compilateur conforme peut toujours compiler avec succès le programme s'il choisit). En plus des erreurs de syntaxe, les violations de contraintes sont la plus proche de dire que quelque chose est illégal. (À l'exception des directives #Error , qui doivent provoquer la rejetation d'une unité de traduction.)

avant C99, C avait un "code implicite int " Règle, qui signifiait que si vous appelez une fonction sans déclaration visible, une déclaration implicite ne serait créée. Cette déclaration serait pour une fonction avec un type de retour de int et avec des paramètres des types (promus) des arguments que vous avez passés. Votre appel somme (1, 3) créerait une déclaration implicite int SUM (int, int) et générer un appel comme si la fonction ont été définis de cette façon.

car il n'est pas défini de cette façon, le comportement est indéfini. (Très probablement, la valeur de l'un des paramètres, peut-être la troisième, sera prise à partir d'un registre arbitraire ou d'un emplacement de mémoire, mais la norme indique rien à propos de ce que l'appel le fera réellement.)

C99 (l'édition de 1999 de la norme ISO C) a chuté la règle implicite int . Si vous compilez votre code avec un compilateur C99 ou ultérieur conforme, le compilateur est tenu de diagnostiquer une erreur pour la somme somme (1, 3) appel. De nombreux compilateurs, pour la compatibilité en arrière avec l'ancien code, imprimeront un avertissement non mortel et généreront un code qui suppose la définition correspond à la déclaration implicite. Et de nombreux compilateurs sont non conformes par défaut et ne peuvent même pas émettre un avertissement. (BTW, si votre compilateur imprimait une erreur ou un message d'avertissement, il est extrêmement utile si vous l'inclurez dans votre question.)

Votre programme est buggy. Un compilateur C conforme doit au moins vous avertir à ce sujet et éventuellement le rejeter. Si vous l'exécutez malgré l'avertissement, le comportement est indéfini.


1 commentaires

Oui, j'ai oublié ajouter #include en question et vous avez raison que j'ai compilé ce code.