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

gcc 4.0 et unsigned char

17 réponses
Avatar
JKB
Bonjour à tous,

Je suis en train de tester gcc 4.0 et j'ai un gros doute.
Considérons le programme suivant :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main()
{
unsigned char *chaine;
strcpy(chaine, "chaine");

return(EXIT_SUCCESS);
}

En compilant avec :

gcc -Wall essai.c

j'obtiens :

essai.c: In function 'main':
essai.c:9: warning: pointer targets in passing argument 1 of 'strcpy'
differ in signedness

Ce que je peux comprendre. Or il existe une option -funsigned-char
qui est censé forcer toutes les chaînes de caractères en unsigned
char. Soit...

-Wall -funsigned-char essai.c
essai.c: In function 'main':
essai.c:9: warning: pointer targets in passing argument 1 of 'strcpy'
differ in signedness

Est-ce que j'ai raté quelque chose ? Ou est-ce un bug dans gcc
(4.0.2 debian) ? J'ai cherché sur le site de gcc et sur usenet sans
succès...

Merci par avance,

JKB

--
En plus c'est simple, je fais ce genre de trucs en g77 depuis des années :
il suffit d'écrire un wrapper en C. Et comme ça, j'ai le meilleur des deux
mondes : la rigueur quasi-monacale du Fortran, et l'exubérance pétulante du C.

10 réponses

1 2
Avatar
Targeur fou
JKB wrote:
Bonjour à tous,

Je suis en train de tester gcc 4.0 et j'ai un gros doute.
Considérons le programme suivant :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main()
{
unsigned char *chaine;
strcpy(chaine, "chaine");


Pointeur vers char non signé chaine non alloué, pas bien.

#define LG 20u

unsigned char chaine[LG+1];
char * src_cs = "chaine";
if (strlen(src_cs) <= LG) { strcpy(chaine, src_cs); }

/* Exprès pour faire plaisir à Charlie, pas de strncpy :-D */

#undef LG



return(EXIT_SUCCESS);
}

En compilant avec :

gcc -Wall essai.c

j'obtiens :

essai.c: In function 'main':
essai.c:9: warning: pointer targets in passing argument 1 of 'strcpy'
differ in signedness

Ce que je peux comprendre. Or il existe une option -funsigned-char
qui est censé forcer toutes les chaînes de caractères en unsigned
char. Soit...

-Wall -funsigned-char essai.c
essai.c: In function 'main':
essai.c:9: warning: pointer targets in passing argument 1 of 'strcpy'
differ in signedness

Est-ce que j'ai raté quelque chose ? Ou est-ce un bug dans gcc
(4.0.2 debian) ? J'ai cherché sur le site de gcc et sur usenet sans
succès...


Pas d'idées à part celles-ci :
- s'assurer que l'option -funsigned-char est bien de portée globale,
ce qui doit être le cas.
- Je ne sais pas comment l'option -funsigned-char affecte la
compilation, mais si c'est un genre de typecast de char vers unsigned
char de toutes les variables typées, le pb pourrait venir du fait que
"chaine", en dur dans ton strcpy, ne soit pas affectée par l'option
-funsigned-char, car c'est une chaine litérale (constante). Ses
éléments sont de type char (d'après ma draft de norme (C99),
$6.4.5).

Merci par avance,

JKB



A+
Regis

Avatar
Antoine Leca
En news:,
JKB va escriure:
Ce que je peux comprendre. Or il existe une option -funsigned-char
qui est censé forcer toutes les chaînes de caractères en unsigned
char. Soit...


Non.

En C (et GCC force cette interprétation), il y a TROIS types char, le type
non signé (unisgned char), le type signé (signed char), et un troisième, que
l'on appelle char tout simplement (plain char en anglais) ; la norme oblige
de plus à ce que le troisième utilise les mêmes représentations que l'un des
deux autres.
Au choix.
Ce choix, c'est justement ce que contrôle l'option -funsigned-char :
par défaut c'est signé (comme c'est la coûtume sur Unix), mais pour avoir
les représentations toujours non-signés c'est l'option qu'il faut prendre.
La différence entre les deux, c'est que (dans la plupart des cas) 'ÿ' vaudra
EOF sans l'option, et 255 avec ; ce qui fait qu'en dehors des États-Unis et
du RUGBIN, beaucoup de gens aime bien cette option ; mais je m'égare.

Cette option ne « réduit » pas le nombre de types à deux (ce que faisait
certains compilateurs pour MS-DOS à la fin des années 80). Donc en
particulier, char* reste différent de unsigned char*, même avec l'option.


Cela étant, c'est un avertissement ; ton code va se comporter comme attendu
(si on suppose que tu alloues de l'espace).


Est-ce que j'ai raté quelque chose ? Ou est-ce un bug dans gcc


De mémoire, c'est le comportement de GCC depuis des lustres (OK, au moins
un, probablement deux mais pas plus). Pour info sans prendre plus de temps à
chercher, une 3.2 donne exactement le même message.


D'un autre côté, il est peut-être possible que le message d'erreur soit
amélioré... Si tu remplaces unsigned par signed, cela donne le même message,
c'est assez rigolo.


Antoine

Avatar
JKB
Le 26-10-2005, à propos de
Re: gcc 4.0 et unsigned char,
Targeur fou écrivait dans fr.comp.lang.c :

JKB wrote:
Bonjour à tous,

Je suis en train de tester gcc 4.0 et j'ai un gros doute.
Considérons le programme suivant :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main()
{
unsigned char *chaine;
strcpy(chaine, "chaine");


Pointeur vers char non signé chaine non alloué, pas bien.


Oui bon, j'ai fait ce test sur un coin de table. Comment ai-je pu
laisser passer ça ?

#define LG 20u

unsigned char chaine[LG+1];
char * src_cs = "chaine";
if (strlen(src_cs) <= LG) { strcpy(chaine, src_cs); }

/* Exprès pour faire plaisir à Charlie, pas de strncpy :-D */

#undef LG



return(EXIT_SUCCESS);
}

En compilant avec :

gcc -Wall essai.c

j'obtiens :

essai.c: In function 'main':
essai.c:9: warning: pointer targets in passing argument 1 of 'strcpy'
differ in signedness

Ce que je peux comprendre. Or il existe une option -funsigned-char
qui est censé forcer toutes les chaînes de caractères en unsigned
char. Soit...

-Wall -funsigned-char essai.c
essai.c: In function 'main':
essai.c:9: warning: pointer targets in passing argument 1 of 'strcpy'
differ in signedness

Est-ce que j'ai raté quelque chose ? Ou est-ce un bug dans gcc
(4.0.2 debian) ? J'ai cherché sur le site de gcc et sur usenet sans
succès...


Pas d'idées à part celles-ci :
- s'assurer que l'option -funsigned-char est bien de portée globale,
ce qui doit être le cas.
- Je ne sais pas comment l'option -funsigned-char affecte la
compilation, mais si c'est un genre de typecast de char vers unsigned
char de toutes les variables typées, le pb pourrait venir du fait que
"chaine", en dur dans ton strcpy, ne soit pas affectée par l'option
-funsigned-char, car c'est une chaine litérale (constante). Ses
éléments sont de type char (d'après ma draft de norme (C99),
$6.4.5).


En fait, si je déclare deux chaînes en unsigned char * et que je
fais un strcpy(chaine_1, chaine_2), je me fais toujours insulter...

JKB

--
En plus c'est simple, je fais ce genre de trucs en g77 depuis des années :
il suffit d'écrire un wrapper en C. Et comme ça, j'ai le meilleur des deux
mondes : la rigueur quasi-monacale du Fortran, et l'exubérance pétulante du C.


Avatar
Harpo
JKB wrote:


En fait, si je déclare deux chaînes en unsigned char * et que je
fais un strcpy(chaine_1, chaine_2), je me fais toujours insulter...


Oui, personnellement, j'en ai pris mon parti, j'évite de faire des
strcpy et d'appeller des fonctions idiotes.

Avatar
Targeur fou
JKB wrote:
Le 26-10-2005, à propos de
Re: gcc 4.0 et unsigned char,
Targeur fou écrivait dans fr.comp.lang.c :

JKB wrote:
Bonjour à tous,




Bonjour,


Je suis en train de tester gcc 4.0 et j'ai un gros doute.
Considérons le programme suivant :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main()
{
unsigned char *chaine;
strcpy(chaine, "chaine");


Pointeur vers char non signé chaine non alloué, pas bien.


Oui bon, j'ai fait ce test sur un coin de table. Comment ai-je pu
laisser passer ça ?

#define LG 20u

unsigned char chaine[LG+1];
char * src_cs = "chaine";
if (strlen(src_cs) <= LG) { strcpy(chaine, src_cs); }

/* Exprès pour faire plaisir à Charlie, pas de strncpy :-D */

#undef LG



return(EXIT_SUCCESS);
}

En compilant avec :

gcc -Wall essai.c

j'obtiens :

essai.c: In function 'main':
essai.c:9: warning: pointer targets in passing argument 1 of 'strcpy'
differ in signedness

Ce que je peux comprendre. Or il existe une option -funsigned-char
qui est censé forcer toutes les chaînes de caractères en unsign ed
char. Soit...

-Wall -funsigned-char essai.c
essai.c: In function 'main':
essai.c:9: warning: pointer targets in passing argument 1 of 'strcpy'
differ in signedness

Est-ce que j'ai raté quelque chose ? Ou est-ce un bug dans gcc
(4.0.2 debian) ? J'ai cherché sur le site de gcc et sur usenet sans
succès...


Pas d'idées à part celles-ci :
- s'assurer que l'option -funsigned-char est bien de portée globale,
ce qui doit être le cas.
- Je ne sais pas comment l'option -funsigned-char affecte la
compilation, mais si c'est un genre de typecast de char vers unsigned
char de toutes les variables typées, le pb pourrait venir du fait que
"chaine", en dur dans ton strcpy, ne soit pas affectée par l'option
-funsigned-char, car c'est une chaine litérale (constante). Ses
éléments sont de type char (d'après ma draft de norme (C99),
$6.4.5).


En fait, si je déclare deux chaînes en unsigned char * et que je
fais un strcpy(chaine_1, chaine_2), je me fais toujours insulter...


Oui, c'est normal, strcpy() prend des char * en paramètre, pas des
unsigned char *. -funsigned-char, comme l'a expliqué Antoine, permet
D'INTERPRETER le signe du type char, i.e, sa représentation sera la
même que celle d'un unsigned char. Et je me suis aussi mépris sur le
sujet comme toi. Ce n'est donc pas un typecast ou un typedef
quelconque, i.e les types char et unsigned char sont bien
distincts...comme en temps normal.
C'est finalement une option assez piégeuse. T'as plusieurs solutions :
- ne pas utiliser cette option et expliciter le typage des variables
(je fais ça)
- utiliser cette option pour choisir une représentation non signée de
toutes les variables typées en char, pourquoi pas...

J'ai une question à mon tour : pourquoi types-tu ta chaine de
caractère en unsigned char * et pas en char * tout simplement ?

A+
Regis



Avatar
JKB
Le 27-10-2005, à propos de
Re: gcc 4.0 et unsigned char,
Targeur fou écrivait dans fr.comp.lang.c :

Oui, c'est normal, strcpy() prend des char * en paramètre, pas des
unsigned char *. -funsigned-char, comme l'a expliqué Antoine, permet
D'INTERPRETER le signe du type char, i.e, sa représentation sera la
même que celle d'un unsigned char. Et je me suis aussi mépris sur le
sujet comme toi. Ce n'est donc pas un typecast ou un typedef
quelconque, i.e les types char et unsigned char sont bien
distincts...comme en temps normal.
C'est finalement une option assez piégeuse. T'as plusieurs solutions :
- ne pas utiliser cette option et expliciter le typage des variables
(je fais ça)
- utiliser cette option pour choisir une représentation non signée de
toutes les variables typées en char, pourquoi pas...

J'ai une question à mon tour : pourquoi types-tu ta chaine de
caractère en unsigned char * et pas en char * tout simplement ?


Parce que j'ai des passages de paramètres (de chaînes) vers des
routines Fortran et que le signed char me pose des problèmes sur
certaines architectures ésotériques.

gcc-3.4 ne sort aucun warning. Est-il possible de faire comprendre
au compilo qu'il doit ne pas afficher les warnings correspondant à
ça ? Du style -Wall -fno quelque chose, mais je n'ai pas trouvé :-(

JKB

--
En plus c'est simple, je fais ce genre de trucs en g77 depuis des années :
il suffit d'écrire un wrapper en C. Et comme ça, j'ai le meilleur des deux
mondes : la rigueur quasi-monacale du Fortran, et l'exubérance pétulante du C.

Avatar
Targeur fou
JKB wrote:
Le 27-10-2005, à propos de
Re: gcc 4.0 et unsigned char,
Targeur fou écrivait dans fr.comp.lang.c :

Oui, c'est normal, strcpy() prend des char * en paramètre, pas des
unsigned char *. -funsigned-char, comme l'a expliqué Antoine, permet
D'INTERPRETER le signe du type char, i.e, sa représentation sera la
même que celle d'un unsigned char. Et je me suis aussi mépris sur le
sujet comme toi. Ce n'est donc pas un typecast ou un typedef
quelconque, i.e les types char et unsigned char sont bien
distincts...comme en temps normal.
C'est finalement une option assez piégeuse. T'as plusieurs solutions :
- ne pas utiliser cette option et expliciter le typage des variables
(je fais ça)
- utiliser cette option pour choisir une représentation non signée de
toutes les variables typées en char, pourquoi pas...

J'ai une question à mon tour : pourquoi types-tu ta chaine de
caractère en unsigned char * et pas en char * tout simplement ?


Parce que j'ai des passages de paramètres (de chaînes) vers des
routines Fortran et que le signed char me pose des problèmes sur
certaines architectures ésotériques.


Je ne comprend pas bien : le type char est le type char, pas signed
char. Il a souvent par défaut la même représentation qu'un signed
char, mais si avec gcc tu utilises l'option -funsigned-char, alors la
repésentation des variables typées en char sera la même que les
unsigned char, où est le problème ?

gcc-3.4 ne sort aucun warning. Est-il possible de faire comprendre
au compilo qu'il doit ne pas afficher les warnings correspondant à
ça ? Du style -Wall -fno quelque chose, mais je n'ai pas trouvé :-(


Bizarre, mon gcc 3.3 Interix râle comme il le faut avec options
-stdÈ9 -pedantic -Wall -funsigned-char si je passe en paramètre un
unsigned char à une fonction qui attend un char.

A+
Regis


Avatar
JKB
Le 27-10-2005, à propos de
Re: gcc 4.0 et unsigned char,
Targeur fou écrivait dans fr.comp.lang.c :

JKB wrote:
Le 27-10-2005, à propos de
Re: gcc 4.0 et unsigned char,
Targeur fou écrivait dans fr.comp.lang.c :

Oui, c'est normal, strcpy() prend des char * en paramètre, pas des
unsigned char *. -funsigned-char, comme l'a expliqué Antoine, permet
D'INTERPRETER le signe du type char, i.e, sa représentation sera la
même que celle d'un unsigned char. Et je me suis aussi mépris sur le
sujet comme toi. Ce n'est donc pas un typecast ou un typedef
quelconque, i.e les types char et unsigned char sont bien
distincts...comme en temps normal.
C'est finalement une option assez piégeuse. T'as plusieurs solutions :
- ne pas utiliser cette option et expliciter le typage des variables
(je fais ça)
- utiliser cette option pour choisir une représentation non signée de
toutes les variables typées en char, pourquoi pas...

J'ai une question à mon tour : pourquoi types-tu ta chaine de
caractère en unsigned char * et pas en char * tout simplement ?


Parce que j'ai des passages de paramètres (de chaînes) vers des
routines Fortran et que le signed char me pose des problèmes sur
certaines architectures ésotériques.


Je ne comprend pas bien : le type char est le type char, pas signed
char. Il a souvent par défaut la même représentation qu'un signed
char, mais si avec gcc tu utilises l'option -funsigned-char, alors la
repésentation des variables typées en char sera la même que les
unsigned char, où est le problème ?


Du temps où j'ai commencé à écrire le soft en question (1989), les
unsigned char étaient les seuls trucs qui permettaient à coup sûr,
sur VAX, sparc32 et i386 de passer des chaînes de caractères. Un
char seul (équivalent à l'époque au signed char) me posait des tas
de problèmes pour traiter les caractères accentués. Des trucs qui
passaient sur VAX ne passaient plus sur sparc32 et les résultats
étaient souvent folkloriques avec les PC. Aujourd'hui, seize ans
après, j'ai un truc qui fait une trentaine de mégaoctets de sources et
j'essaye de trouver une manip qui m'évite d'aller trifouiller dans
un code qui fonctionne à merveille pour éviter ces warnings qui ne
correspondent dans mon cas à rien.

À force de chercher, j'ai trouvé :
-Wall -funsigned-char -Wno-pointer-sign
qui résout mon problème.

Au passage, il y a un truc sournois dans gcc-4.0 :

unsigned char caractere;
if ((caractere = getc(fichier)) == EOF)
{
break;
}

Je sais bien que getc() retourne un int. A priori, il est dans
l'intervalle 0 - 255 ou -128 - 127. Le cast dans le type du
caractère devrait être automatique, non ?
Le test est toujours faux. Avec les 2.x et 3.x, le test était vrai à
la fin du fichier. gcc-4.0 impose :

int caractere;
if ((caractere = getc(fichier)) == EOF)
{
break;
}

Je ne vois pas bien pourquoi. Sachant que si je rajoute juste après
le test :

unsigned char caractere;
if ((caractere = getc(fichier)) == EOF)
{
break;
}
printf("%dn", caractere == EOF);

je vois bien une valeur non nulle arriver en fin de fichier.
Décidément, gcc-4.0 n'est pas encore tout à fait au point...

JKB

--
En plus c'est simple, je fais ce genre de trucs en g77 depuis des années :
il suffit d'écrire un wrapper en C. Et comme ça, j'ai le meilleur des deux
mondes : la rigueur quasi-monacale du Fortran, et l'exubérance pétulante du C.



Avatar
Harpo
JKB wrote:


À force de chercher, j'ai trouvé :
-Wall -funsigned-char -Wno-pointer-sign
qui résout mon problème.


Je pense que recourir aux options du compilateur n'est pas la meilleure
technique.
j'aurais plutôt fait :
#define uchar unsigned char
et ensuite mouliner les programmes pour changer 'char' par 'uchar'
ou , à la main, sous Vim
:map <F2> :s/char/uchar/^M/^M<F2>
et ensuite appuyer sur la touche fonction F2
Attention, il y a un piège... :-)

Avatar
screetch
Harpo wrote:
Attention, il y a un piège... :-)


je pense qu'il y a plus d'un piège ^^

un piège étant que si tu appuies deux fois sur F2 tu te retrouves avec
un fichier complétement pourri, avec des uuchar partout. de plus si tu
as des unsigned char tu vas te retrouver avec des unsigned uchar, et
enfin si dans tes commentaires tu as ecrit char (voire un mot contenant
char, genre echarper) ca va aussi etre remplacer par uchar (eucharper)

ou encore si tu as des fonctions dont le nom comprend char.

bref que du bonheur :)

1 2