OVH Cloud OVH Cloud

sscanf et unsigned char

13 réponses
Avatar
News
Bonjour,
je me pose une question concernant la lecture d'une chaîne avec
sscanf(buffer,"%02X",&byte);
je récupère donc un octet, que je veux mettre dans un unsigned char.
Mais gcc m'engueule en me disant : "format unsigned int, arg type
différent (arg 3)".
Seulement, récupérer, comme gcc préfère, dans un unsigned int (donc 4
octets) est plus emmerdant après, car on ne sait pas dans quel octet
c'est lu selon le little/big endian et ça peut faire n'importe quoi lors
du memcopy qui suit...

TP

10 réponses

1 2
Avatar
Charlie Gordon
"News" wrote in message
news:41a35b3f$0$31421$
Bonjour,
je me pose une question concernant la lecture d'une chaîne avec
sscanf(buffer,"%02X",&byte);
je récupère donc un octet, que je veux mettre dans un unsigned char.
Mais gcc m'engueule en me disant : "format unsigned int, arg type
différent (arg 3)".
Seulement, récupérer, comme gcc préfère, dans un unsigned int (donc 4
octets) est plus emmerdant après, car on ne sait pas dans quel octet
c'est lu selon le little/big endian et ça peut faire n'importe quoi lors
du memcopy qui suit...


Mais non, pas de problème, sscanf convertit la valeur dans un unsigned int et tu
la stockes ensuite dans un unsigned char, l'ordre des octets n'a rien a voir
avec ça.

unsigned int val;
unsigned char uc;
sscanf(buffer, "%02X", &val);
// les trois lignes suivantes sont équivalentes
uc = val;
uc = (unsigned char)val;
uc = val & ((1 << CHAR_BIT) - 1);

// la deuxieme est la plus explicite, le cast peut etre utile avec certains
compilo très bruyants sur les conversions implicites avec perte de précision
(VC++)

Chqrlie.

Avatar
AG
News wrote:
Bonjour,
je me pose une question concernant la lecture d'une chaîne avec
sscanf(buffer,"%02X",&byte);
je récupère donc un octet, que je veux mettre dans un unsigned char.
Mais gcc m'engueule en me disant : "format unsigned int, arg type
différent (arg 3)".
Seulement, récupérer, comme gcc préfère, dans un unsigned int (donc 4
octets) est plus emmerdant après, car on ne sait pas dans quel octet
c'est lu selon le little/big endian et ça peut faire n'importe quoi lors
du memcopy qui suit...

TP
un petit cast de ton int en unsigned char et le tour est joué.


Avatar
News
"News" wrote in message
news:41a35b3f$0$31421$

Bonjour,
je me pose une question concernant la lecture d'une chaîne avec
sscanf(buffer,"%02X",&byte);
je récupère donc un octet, que je veux mettre dans un unsigned char.
Mais gcc m'engueule en me disant : "format unsigned int, arg type
différent (arg 3)".
Seulement, récupérer, comme gcc préfère, dans un unsigned int (donc 4
octets) est plus emmerdant après, car on ne sait pas dans quel octet
c'est lu selon le little/big endian et ça peut faire n'importe quoi lors
du memcopy qui suit...



Mais non, pas de problème, sscanf convertit la valeur dans un unsigned int et tu
la stockes ensuite dans un unsigned char, l'ordre des octets n'a rien a voir
avec ça.

unsigned int val;
unsigned char uc;
sscanf(buffer, "%02X", &val);
// les trois lignes suivantes sont équivalentes
uc = val;
uc = (unsigned char)val;
uc = val & ((1 << CHAR_BIT) - 1);

// la deuxieme est la plus explicite, le cast peut etre utile avec certains
compilo très bruyants sur les conversions implicites avec perte de précision
(VC++)

Chqrlie.


C'est bien la solution 2 que j'avais adopté.


Une réponse de Michael Mair sur la liste gnu.gcc.help a été très
explicite : comme sscanf renvoie un int sur 4 octets, il faut lui filer
un champ de la même taille pour éviter le segmentation fault alléatoire.
Donc pas un unsigned char.


Avatar
Antoine Leca
En 41a35b3f$0$31421$, TP va escriure:
je me pose une question concernant la lecture d'une chaîne avec
sscanf(buffer,"%02X",&byte);
je récupère donc un octet,


Oui.

que je veux mettre dans un unsigned char.


sscanf(buffer,"%02hhX",&byte);

C99 seulement.
Si tu veux être portable C90, regarde ce que disent les autres.

Note que "%02hx" aurait stocké dans un unsigned short, et c'est compatible
C90/Unix V7 etc., mais ce n'est pas ce que tu veux.

Mais gcc m'engueule en me disant : "format unsigned int, arg type
différent (arg 3)".


Il a bien raison (de t'engueuler), tu allais faire une bêtise...

En gros, tu te trompes parce que tu pars du principe que puisque ton format
(hérité de printf) ne gère que deux chiffres hexadecimaux donc un octet,
alors printf va lire un argument unsigned char; c'est inexact: printf attend
dans ce cas un argument unsigned int; essaye donc de passer 345 pour voir ce
que tu récupères... Et donc dans l'autre sens, scanf stocke le résultat de
la conversion dans un unsigned int.

Si tu veux passer un argument unsigned char, avec C99 tu peux essayer
printf("%02hhX", c);


Seulement, récupérer, comme gcc préfère,


gcc ne préfère rien, il te signale seulement que tu n'es pas cohérent entre
ton format et tes paramètres. Tu peux corriger l'un (comme ci-dessus) ou
l'autre (comme expliqué par les autres). Mais tu ne peux pas laisser cela
ainsi.


Antoine

Avatar
Emmanuel Delahaye
News wrote on 23/11/04 :
je me pose une question concernant la lecture d'une chaîne avec
sscanf(buffer,"%02X",&byte);
je récupère donc un octet, que je veux mettre dans un unsigned char.


Marche pas.

Mais gcc m'engueule en me disant : "format unsigned int, arg type différent
(arg 3)".


Par exemple...

unsigned byte;

sscanf(buffer,"%02X",&byte);

Seulement, récupérer, comme gcc préfère, dans un unsigned int (donc 4 octets)
est plus emmerdant après, car on ne sait pas dans quel octet c'est lu selon
le little/big endian et ça peut faire n'importe quoi lors du memcopy qui


Pourquoi un memcpy(). Qu'est-ce qui ne vas pas avec '=' ? Montre ton
code et explique ce que tu veux faire exactement...

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Clearly your code does not meet the original spec."
"You are sentenced to 30 lashes with a wet noodle."
-- Jerry Coffin in a.l.c.c++

Avatar
Emmanuel Delahaye
Charlie Gordon wrote on 23/11/04 :

je récupère donc un octet, que je veux mettre dans un unsigned char.


uc = val & ((1 << CHAR_BIT) - 1);


Euh, non. Le monsieur, il a parlé d'octet...

uc = val & 0xFF;

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Mal nommer les choses c'est ajouter du malheur au
monde." -- Albert Camus.


Avatar
Charlie Gordon
"Emmanuel Delahaye" wrote in message
news:
Charlie Gordon wrote on 23/11/04 :

je récupère donc un octet, que je veux mettre dans un unsigned char.


uc = val & ((1 << CHAR_BIT) - 1);


Euh, non. Le monsieur, il a parlé d'octet...

uc = val & 0xFF;


Je l'attendais celle-là...
J'aurais pu écrire ce que tu proposes, mais la version "standard" pédante
devrait aussi faire l'affaire, non ?
Ou alors : val & UCHAR_MAX
On va bien trouver une architecture exotique (ou plutot chaotique) ou ces
écritures auraient un autre sens...
De toute facon CHAR_BIT >= 8, sscanf() n'a lu que 2 chiffres hexadécimaux, et
cette discussion est largement au delà des compétences de l'OP, sans compter que
je n'ai même pas testé le résultat de sscanf(), ni même la pertinence du format
%02X...

Chqrlie.



Avatar
News
News wrote on 23/11/04 :

je me pose une question concernant la lecture d'une chaîne avec
sscanf(buffer,"%02X",&byte);
je récupère donc un octet, que je veux mettre dans un unsigned char.



Marche pas.

Mais gcc m'engueule en me disant : "format unsigned int, arg type
différent (arg 3)".



Par exemple...

unsigned byte;

sscanf(buffer,"%02X",&byte);

Seulement, récupérer, comme gcc préfère, dans un unsigned int (donc 4
octets) est plus emmerdant après, car on ne sait pas dans quel octet
c'est lu selon le little/big endian et ça peut faire n'importe quoi
lors du memcopy qui



Pourquoi un memcpy(). Qu'est-ce qui ne vas pas avec '=' ? Montre ton
code et explique ce que tu veux faire exactement...

J'ai finalement fait le sscanf sur un unsigned int, ensuite casté en

unsigned char et je sais donc où taper pour récupérer mon char.
Merci pour toutes vos réponses.
T.P.


Avatar
James Kanze
"Charlie Gordon" writes:

|> "News" wrote in message
|> news:41a35b3f$0$31421$

|> > je me pose une question concernant la lecture d'une chaîne avec
|> > sscanf(buffer,"%02X",&byte);
|> > je récupère donc un octet, que je veux mettre dans un unsigned char.
|> > Mais gcc m'engueule en me disant : "format unsigned int, arg type
|> > différent (arg 3)".
|> > Seulement, récupérer, comme gcc préfère, dans un unsigned int (donc 4
|> > octets) est plus emmerdant après, car on ne sait pas dans quel octet
|> > c'est lu selon le little/big endian et ça peut faire n'importe quoi lors
|> > du memcopy qui suit...

|> Mais non, pas de problème, sscanf convertit la valeur dans un
|> unsigned int et tu la stockes ensuite dans un unsigned char, l'ordre
|> des octets n'a rien a voir avec ça.

|> unsigned int val;
|> unsigned char uc;
|> sscanf(buffer, "%02X", &val);
|> // les trois lignes suivantes sont équivalentes

Je mettrais bien un « assert( val ) <= UCHAR_MAX ) » ici.

|> uc = val;
|> uc = (unsigned char)val;
|> uc = val & ((1 << CHAR_BIT) - 1);

|> // la deuxieme est la plus explicite, le cast peut etre utile avec
|> certains compilo très bruyants sur les conversions implicites avec
|> perte de précision (VC++)

Il se plain d'une conversion explicite ?

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
Avatar
James Kanze
"Charlie Gordon" writes:

|> "Emmanuel Delahaye" wrote in message
|> news:
|> > Charlie Gordon wrote on 23/11/04 :

|> > >> je récupère donc un octet, que je veux mettre dans un unsigned
|> > >> char.

|> > > uc = val & ((1 << CHAR_BIT) - 1);

|> > Euh, non. Le monsieur, il a parlé d'octet...

|> > uc = val & 0xFF;

|> Je l'attendais celle-là...
|> J'aurais pu écrire ce que tu proposes, mais la version "standard"
|> pédante devrait aussi faire l'affaire, non ?

Ça dépend du cahier de charges -- les deux ne font pas la même chose sur
toutes les machines. Comme a dit Emmanuel, il a parlé d'« octet », non
de multiplet ou de byte. Il faut donc croire que le cahier de charges
précis huit bits, quelque soit la taille d'un unsigned char (et donc de
la valeur de CHAR_BIT) sur la machine en question. Si c'est le cas, 0xFF
est correct, et ((1 << CHAR_BIT) - 1) est incorrect.

|> Ou alors : val & UCHAR_MAX

|> On va bien trouver une architecture exotique (ou plutot chaotique)
|> ou ces écritures auraient un autre sens...

Les Unisys 2200 sont encore fabriqué aujourd'hui. Mais indépendamment de
la machine, il y a la question de ce que le code dit au lecteur. Ce que
tu as écris dit qu'on veut lire quelque chose de la taille d'un
multiplet sur la machine en question, que ce soit 8, 9 ou 32 (pour ne
citait que ceux que je sais existent sur des machines modernes), écrire
0xFF dit qu'on veut 8 bits, quelque soit la taille d'un multiplet.

Comme j'ai dit, la forme « correcte » dépend du cahier de charges.

|> De toute facon CHAR_BIT >= 8, sscanf() n'a lu que 2 chiffres
|> hexadécimaux, et cette discussion est largement au delà des
|> compétences de l'OP, sans compter que je n'ai même pas testé le
|> résultat de sscanf(), ni même la pertinence du format %02X...

P't-êt' ben. Mais alors, si %02X signifie qu'on veut 8 bits, pourquoi
utiliser une expression complexe qui pourraient, sur certaines machines,
donner un résultat autre, plutôt qu'une expression simple et parlante
qui marche partout ?

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
1 2