7
votes

Valeur du type booléen changé dans c

J'ai remarqué que dans C, ma variable booléenne est en quelque sorte changée d'une manière que je ne comprends pas. xxx pré>

si je saisie une valeur de 1 code> pour x code> et n'importe quelle valeur pour y code> ( 1 code> dans cet exemple): p>

x: 1
x is 1
y: 1
x is 0
y is 1


3 commentaires

Sidenote: Vérifiez toujours la valeur de retour de Scanf Fonctions. Sinon, vous ferez l'expérience du comportement indéfini lorsque l'utilisateur donne une entrée non valide (dans ce cas non numérique).


Gagnez du temps, activez les avertissements de complier. bool x, y; ... Scanf ("% d", & x); aurait dû vous avertir.


@chux je suis d'accord, j'ai ajouté cela comme une réponse.


7 Réponses :


7
votes

OK, deux points ici.

  1. La taille de bool est définie par la mise en œuvre.
  2. Il n'y a pas de spécificateur de format défini pour bool type dans la norme.

    Alors, tandis que Numérisation la valeur, passant l'adresse d'un bool comme argument pour % d est mauvais Voir note comme le type fourni n'est pas identique au type attendu.

    Vous pouvez utiliser un entier intermédiaire, numériser la valeur en cela et (après validation ou transformation sur true et false macros) Attribuer le résultat retour à BOOL variable de type.

    pour Impression , cependant, en raison de la promotion des arguments par défaut, un bool peut être un candidat à l'argument pour % d sans problème .


    Remarque:

    % d avec * scanf () attend que l'argument soit un int * , fournissant plutôt un bool * va causer comportement non défini .

    liés, citant du chapitre § 7.21.6.2, paragraphe 10

    [....] Sauf si une suppression d'affectation n'a été indiquée par un * , le Le résultat de la conversion est placé dans l'objet pointé par le premier argument suivant L'argument format qui n'a pas déjà reçu de résultat de conversion. si cet objet n'a pas de type approprié ou si le résultat de la conversion ne peut pas être représenté Dans l'objet, le comportement est indéfini.


8 commentaires

Pourriez-vous expliquer davantage sur la façon dont "transmettre l'adresse d'un bool comme argument de % d n'est pas bon"?


Celui-ci est peut-être utile: printf ("\ n_bool:% zu \ nint:% zu", Tailleof (_bool), Tailleof (int)); montrant qu'ils n'ont peut-être pas la même taille. Sur ma machine (GCC 4.8.5), j'obtiens: _bool: 1 et int: 4 .


@Andrekampling Pas extrêmement pertinent car il est toujours un comportement non défini pour utiliser le spécificateur de format incompatible, même pour deux types qui ont la même taille


@ Mm pour développer, comme, pour int et float . L'alignement joue également un rôle.


@ M.m aussi, édité la dernière partie pour le rendre plus clair, c'est mieux?


@ M.m monsieur, même si bool est un typedef pour un int ?


@ M.m Si je peux, il n'est pas nécessaire de ne pas être un int * , strictement, il peut s'agir d'un pointeur sur un type d'entier signé. Corrigez-moi si j'ai tort, s'il-vous plait.


@ M.m Merci de corriger alors, j'ai mis à jour la réponse.



8
votes

Vous passez une adresse de la variable booléenne à scanf () code> qui attend la variable de type int * code>. Cela invoquera un comportement non défini et vous risquez d'obtenir des résultats erronés ou même de crash.

Pour résoudre ce problème, utilisez temporairement int code> pour stocker la numérisation d'une valeur booléenne (comme INT), et après cela à une variable booléenne. p>

Démo strong> p>

bool x, y;
int tmp;

printf("x: ");
scanf("%d", &tmp);
x = tmp;


1 commentaires

x = (TMP! = 0? true: false); z-> x = !! TMP;



7
votes

A bool n'est pas un int . Le lire avec le spécificateur de format % d pour un int est un comportement indéfini.

par 7.21.6.2 Le FSCANF fonction , paragraphe 13 de la norme C :

Si une spécification de conversion n'est pas valide, le comportement est indéfini.

Notez que le paragraphe 9 de 7.21.6.1 le fprintf fonction états:

Si une spécification de conversion n'est pas valide, le comportement est indéfini. Si un argument n'est pas le type correct pour le Spécification de conversion correspondante, le comportement est non défini.

Mais c'est pour fprintf () , pas fscanf () . Les spécificateurs de format sont beaucoup plus stricts pour les fonctions SCANF () Comme il n'y aura aucun argument de promotion que permet un format tel que % d à "fonctionner" pour un char ou bool , qui est promu à int Pour un printf () appel. Les fonctions scanf () sont transmises l'adresse de l'argument, et si ce que l'adresse fait référence à une taille erronée de ce qui est attendu par le spécificateur de format, le comportement non défini sera Résultat - tels que des modifications inexpliquées de une autre variable .


16 commentaires

Ceci est faux . La spécification de conversion est non invalide ici. Voir Ceci


@Souravghosh Comment savez-vous?


@Souravghosh: Mais n'est-ce pas exactement ce que vous dites dans votre réponse ???


@PaulR Non monsieur, la spécification de conversion est Fine , c'est l'argument qui ne s'inscrit là-bas.


@Souravghosh hein? De toute évidence, les gens veulent dire "le spécificateur de conversion est faux pour l'argument fourni"


@SOURAVGHOSH: Le point est que la spécification de conversion et le type du paramètre ne correspondent pas. C'est une réponse parfaitement bonne si vous le lisez attentivement.


@SOURAVGHOSH Non Monsieur, la spécification de conversion va bien, c'est l'argument qui l'incompatible. Comment la spécification de conversion peut-elle être "bien" si elle ne correspond pas à l'argument? C'est la définition d'une spécification de conversion non valide: "Sous le contrôle de la chaîne pointée par format spécifiant les séquences d'entrée admissibles et la manière dont ils doivent être convertis pour une affectation, en utilisant des arguments ultérieurs en tant que pointeurs vers les objets. recevoir l'entrée convertie. "


@PaulR mal et non valide sont utilisés dans un contexte différent, comme je l'ai lu. En outre, j'ai lié une question de mienne dans ce contexte.


@ user694733 c'est une note de bas de page explicative. Et dans cette copie de la norme C , Note de bas de page 282 se lit "282) Voir" "Directions de la bibliothèque futures" (7.31.11). "


Tout d'abord, je viens de commencer à apprendre C deux jours il y a deux jours, je ne comprends donc pas 90% des choses dans ce PDF. De plus, ces commentaires me rendent simplement plus confus quant à ce qui est la cause du problème. Pour l'instant, cela ressemble à une question de sémantique pour moi.


@ user694733 OK, vous citez la section FPRRTINF () , paragraphe 9. La phrase suivante n'est pas au paragraphe 13 de la section FSCANF () que j'ai citée. Je pense que la section FSCANF () est plus appropriée, en particulier depuis fprintf () Spécificateurs de format de facto Autoriser beaucoup de "pont" En raison de la promotion de l'argument, qui n'aidera pas les fonctions scanf () .


@Andrewhenle je me sens comme un idiot maintenant: P désolé. Supprimer des commentaires.


@ user694733 qui était utile, explique probablement certains des commentaires autres Downvotes, comme il y a no référence à l'argument ne correspondant pas à la spécification de conversion Dans la section FSCANF de la norme.


Lire le FSCANF DOCS, je pense toujours qu'il peut y avoir un problème. Je pense que vous auriez dû citer le paragraphe 10, précisément "... Si cet objet n'a pas de type approprié, ni ..., le comportement est indéfini" . Je crois que le paragraphe 13 ne couvre que la syntaxe de spécificateur de conversion malformée (comme non existant % k ).


@ user694733 Je vais devoir reformuler le paragraphe 10 maintenant. : - / J'avais vu cela comme faisant référence au traitement des données d'entrée, mais à la fin, il passe à la rédaction de la conservation des résultats de la conversion.


C'est bien que cette réponse met l'accent sur % d pas un bool ou int , mais un int * .



5
votes

bool est un type de données différent, puis int , et il est susceptible d'être un seul octet.

scanaf n'est pas TYPE -Safe fonction, vous le disez avec le spécificateur de conversion % d qui s'attend à Pointeur sur un Int et scanaf n'a aucun moyen de savoir que Vous avez passé le pointeur à bool au lieu de pointeur sur un int . Ensuite, vous obtiendrez comportement indéfini .

clang compilateur généré avertissement: xxx


0 commentaires

0
votes

Considérez le programme suivant

scanf("%d", &y);


2 commentaires

Connaissez-vous sur Tailleof ?


@ Mm je l'ai trouvé plus illustratif de cette façon.



0
votes

ou peut-être (si la chaîne d'entrée contient true ou est 1 retournera 1 - sinon 0 ) xxx


2 commentaires

Sans le !! , la valeur de retour serait la même. Je suppose un problème de style.


Dans ce cas oui



3
votes

Toutes les autres réponses sont techniquement correctes, mais ne vous aidez pas vraiment.

Votre problème principal n'est pas X ni Y, mais le fait que vous ne soyez pas en mesure de déboguer les problèmes de programmation les plus triviaux vous-même. Ceci est facile à réparer - Activer les avertissements du compilateur (si vous utilisez gcc , ajoutez l'option -wall ). COMPILER vous informera d'une erreur comme celle-ci et beaucoup d'autres autres. Pas besoin de venir à Stackoverflow à chaque fois :)


0 commentaires