Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Un exemple de cast utile sans pointeur

53 réponses
Avatar
Marc Boyer
Je me permets de vous demander un brin d'aide, encore.

Je cherche un exemple simple où la conversion par
cast est nécessaire. Je trouve rien sans devoir
introduire des pointeurs...

Marc Boyer
--
Lying for having sex or lying for making war? Trust US presidents :-(

10 réponses

2 3 4 5 6
Avatar
Antoine Leca
Richard Delorme va escriure:
#include <stdio.h>
int x = 1234;
printf ("%ldn", (long) x);
[...] illustre la nécessité du cast explicite dans les fonctions à


nombre variable d'arguments.


« Nécessité » (sic) est trop fort. Il faut du contexte. Sinon tu vas finir
par écrire

int i;
/*...*/
printf("%d", (int)i);

ce qui devient comique.

Et cela n'explique pas pourquoi il faudrait « surtyper » un int en long.

Maintenant, si ce que tu veux dire, c'est que, dans le cas où une fonction à
nombre variable d'arguments attend un long (ou un long double, ou un long
long, ou un type redéfinissable comme wchar_t ou size_t ou intmax_t ou
uint32_t), il faut transtyper, alors d'accord. C'est le problème des
fonctions à nombre variable d'arguments. Et en général on évite comme la
peste d'obliger le passage d'arguments avec des types pas naturels.
Donc dans la réalité, on a plus souvent affaire à des transtypages vers int
(depuis un type qui peut éventuellement être stocké de manière plus étendu,
comme par exemple LONGBOOL avec Windows), ou bien à des transtypages vers un
dénominateur commun, comme le transtypage de size_t en unsigned long avec le
format %lu en ANSI C89. Pas des « surtypages » int en long.

Le problème ici, c'est que l'exemple, à force d'être épuré, paraît
compliquer quelque chose qui peut être écrit de manière beaucoup plus simple
(comme tu l'as toi-même fait remarquer de manière humoristique).


Antoine



Avatar
Richard Delorme

Peut-être l'utilisation de fgetc(), qui retourne un int qui est
« souvent » un char.

FILE *pFichier = ...
int n;

while ((n = fgetc(pFichier)) != EOF)
{
char c = (char)n;


Qu'est-ce qui ne vas pas avec « char c = n; » ?

--
Richard

Avatar
Guillaume
int n;

while ((n = fgetc(pFichier)) != EOF)
{
char c = (char)n;


Qu'est-ce qui ne vas pas avec « char c = n; » ?


Tu ne peux pas affecter un int à un char directement sans cast,
puisqu'il y a une perte potentielle d'information (le "char" étant
généralement capable de contenir moins de valeurs différentes
que le "int"). Un bon compilateur devrait t'envoyer un warning. Sauf
si, sur la plateforme particulière sur laquelle tu bosses, char <=> int.
Mais pour rester portable, il faut "caster".

Note: certains compilateurs te donneront un warning à la compilation,
d'autres à l'édition de liens (un compilateur Microsoft VC 5.0 ou 6.0,
il me semble), d'autres pas du tout.


Avatar
Marc Boyer
Antoine Leca wrote:

if (isprint((unsigned char)c)) {


Au secours ! Transtypage indéfini !


Mais bon, imaginons le code
char c=rand()?'x':'1';

1) est-ce que ce code est bon ? Ais-je le
droit d'affecter 'x' à un char ?
2) comment je peux tester que c'est un chiffre
avec isdigit ?

Et pour éviter cela, il faut _toujours_ utiliser int pour les variables
caractères, pas char.


Enseigner le C est une école d'humilité.

De plus, mon argument, c'est justement qu'il faut pouvoir encoder deux
choses différentes: 'ÿ' et EOF. Et pour cela, quand on joue avec le résultat
des fonctions getc() et compagnie, cela oblige à utiliser des int, les char
ne suffisent pas.


Pour ma culture, 'ÿ', c'est une constante de quel type ?

Car j'ai bien compris que le résultat de getc[har] était
un int pour pouvoir encoder tous les chars *et* EOF.
J'ai encore du mal avec le prototype de ungetc (le coup
du paramêtre int reconvertit en unsigned char, j'ai du mal).
Mais bon, les caractères, c'est quoi finalement en C ?

Marc Boyer
--
Lying for having sex or lying for making war? Trust US presidents :-(


Avatar
Antoine Leca
En c107e3$pid$, Marc Boyer va escriure:
Antoine Leca wrote:

if (isprint((unsigned char)c)) {


Au secours ! Transtypage indéfini !


Mais bon, imaginons le code
char c=rand()?'x':'1';

1) est-ce que ce code est bon ?


Défini « bon »
Correct : oui.
Optimum : je dirais que non, parce que j'aurais préféré voir

int c = rand() ? 'x' : '1';

(Note bien que je peux être affirmatif sur le premier point, mais le second
est un jugement de valeurs).

Ais-je le droit d'affecter 'x' à un char ?


Oui (toujours). Et idem pour la formule ci-dessus, parce que tu sais que à
la fois 'x' et '1' sont représentables dans un char.

2) comment je peux tester que c'est un chiffre
avec isdigit ?


Bon, si tu as « typé » c en char, il faut effectivement, comme l'as écrit
Jean-Marc, transtyper en unsigned char. Sur ce point, il as parfaitement
raison, je ne le lui ai jamais disputé cela.

Pour ma culture, 'ÿ', c'est une constante de quel type ?


int (en C ; char en C++, c'est une différence entre les deux).


Mais bon, les caractères, c'est quoi finalement en C ?


Norme C (ici N869)

3.5 character
bit representation that fits in a byte

Ce qui nous mène à

3.4 byte
addressable unit of data storage large enough to hold any member of
the basic character set of the execution environment

Et ce machin (le basic bidule chouette environment), c'est défini par
l'implémentation, mais cela doit contenir tous les caractères imprimables
ASCII (sauf @ $ `), avec des représentations positives de surcroît. Tu auras
peut-être déduit que 'ÿ' peut donc avoir une représentation négative (c'est
la cas qu'évoquait Jean-Marc). Donc pour en revenir à ton exemple, avec ma
correction, si tu veux utiliser 'ÿ' à la place de ton 'x', et ensuite
pouvoir utiliser isdigit(), il faut écrire

int c = rand() ? (unsigned char)'ÿ' : '1';

L'arbre des types de ce bout de code est un poëme :
'ÿ' est un int, éventuellement négatif
(unsigned char)'ÿ' est un caractère non signé, donc positif
il est promu en int par (et pour) l'opération ? :
'1' est un int
le résultat de ? : est donc un int, pas de problème à ce niveau
on initialise un int avec un int, pas de problème non plus; notons c est
toujours positif, et peut-être passé à isdigit()

Dans le cas du code
char c = rand() ? 'ÿ' : '1';

'ÿ' est un int, éventuellement négatif (si char est signé)
'1' est un int (positif)
le résultat de ? : est donc un int, positif ou négatif
on initialise un char avec un int, il y a conversion; pas de changement de
signe intempestif cependant.
Si char est signé et 'ÿ' est encodé en Latin-1, c contient -1; si tu le
passes à isdigit(), tu as perdu. Et si tu passes n'importe quel autre
caractère avec un encodage négatif, tu dois compter sur le bon vouloir de
l'implémentation pour te donner le comportement attendu (le comportement est
indéfini d'après la norme).


Antoine



Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Marc Boyer
wrote:

Pour ma culture, 'ÿ', c'est une constante de quel type ?


int.

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?lib=cpp
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/

Avatar
Emmanuel Delahaye
In 'fr.comp.lang.c', Marc Boyer
wrote:

#include <stdio.h>

int x = 1234;

printf ("%ldn", (long) x);


Pourquoi imprimer un long quand on a un int ?
C'est juste pour l'exemple où il y a une raison qui
m'échappe.


OK, soyons un peu plus realiste :

#include <stdio.h>

int main (void)
{
char s[BUFSIZ];

printf ("sizeof s = %lun", (unsigned long) sizeof s);

return 0;
}

--
-ed- [remove YOURBRA before answering me]
The C-language FAQ: http://www.eskimo.com/~scs/C-faq/top.html
C-reference: http://www.dinkumware.com/manuals/reader.aspx?lib=cpp
FAQ de f.c.l.c : http://www.isty-info.uvsq.fr/~rumeau/fclc/


Avatar
Richard Delorme
int n;

while ((n = fgetc(pFichier)) != EOF)
{
char c = (char)n;



Qu'est-ce qui ne vas pas avec « char c = n; » ?



Tu ne peux pas affecter un int à un char directement sans cast,
puisqu'il y a une perte potentielle d'information (le "char" étant
généralement capable de contenir moins de valeurs différentes
que le "int"). Un bon compilateur devrait t'envoyer un warning. Sauf
si, sur la plateforme particulière sur laquelle tu bosses, char <=> int.
Mais pour rester portable, il faut "caster".


Si je comprends mal, le cast supprime le problème de la perte
potentielle d'information ?
On peut justifier du cast pour quelques raisons :
- documentaire : pour signaler que la conversion vers un type plus
étroit est volontaire de la part du programmeur.
- protectrice : pour se protéger des avertissements abusifs de
certains compilateurs.
- imitatrice : pour faire comme en Java, où le cast est obligatoire.
- etc.
A mon avis, toutes ces raisons sont mauvaises, et elles n'ont qu'une
conséquence, rendre le code plus lourd et moins lisible. Quoiqu'il en
soit, le cast ici n'est pas obligatoire, et le mettre ne rend pas le
programme portable.

Note: certains compilateurs te donneront un warning à la compilation,
d'autres à l'édition de liens (un compilateur Microsoft VC 5.0 ou 6.0,
il me semble), d'autres pas du tout.


A noter que dans l'exemple donné, il est impossible que la conversion de
n en char introduise une perte d'information, tout simplement parce que
fgetc, quand il ne retourne pas EOF, retourne oligatoirement une valeur
représentable par un char. Donc le « bon » compilateur ne devrait pas
produire de warning inutile ici.



Avatar
Jean-Marc Bourguet
"Antoine Leca" writes:

2) comment je peux tester que c'est un chiffre
avec isdigit ?


Bon, si tu as « typé » c en char, il faut effectivement, comme l'as
écrit Jean-Marc, transtyper en unsigned char. Sur ce point, il as
parfaitement raison, je ne le lui ai jamais disputé cela.


Comme c'est le seul point que je pensais faire, je me demande ce que
tu me disputes.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org


Avatar
Antoine Leca
Jean-Marc Bourguet va escriure:
Comme c'est le seul point que je pensais faire, je me demande ce que
tu me disputes.


Utiliser char (et non pas int) comme type pour les variables.


Antoine

2 3 4 5 6