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

[gcc 4.0.2] probleme cast et shift

10 réponses
Avatar
Truc Muche
soit le fragment de code suivant :

-------------------------------
struct mastruct {
unsigned int start,stop;
};


static int s_addrcmp_for_qsort(const void *a,const void *b )
{
const struct mastruct *line_a=(const struct mastruct *)a,
*line_b=(const struct mastruct *)b;
unsigned int result;


result= ((line_a->start)>>2) - ((line_b->start)>>2);

return result;
}

-------------------------

je compile en -Wall -Wextra, etc... avec un gcc 4.0.2, et celui ci se
fache en me disant :
warning: cast discards qualifiers from pointer target type
sur la ligne : result= ((line_a->start)>>2) - ((line_b->start)>>2);
Si quelqu'un pouvait me dire ce que je fais de mal, je lui en serais
éternellement reconnaissant....

TM.

10 réponses

Avatar
AG
Je ne saurais pas dire pourquoi gcc gueule. Par contre, je sais que ce
que tu fais est dangereux. Peut être est-ce pour cela que gcc émet un
warning :

soit tu appelles toujours la fonction s_addrcmp_for_qsort() avec,
comme argument, des struct mastruct. Auquel cas je ne vois pas
l'intérêt d'utiliser les types const void * en argument de fonction.
Soit tu l'utilises sur des types qui ne sont pas des struct mastruct,
et là tu risques d'avoir des problèmes, car à priori, rien ne garanti
que la représentation mémoire de ta structure soit la même que celle
des autres types sur lesquel tu l'appliques. En particulier, il
pourrait y avoir des bits de padding entre tes deux unsigned int, ce
qui causerait des problèmes. Il existe une option gcc pour compiler
sans bits de padding dans les structures.

Si ça peut aider.

AG.

"Truc Muche" a écrit dans le message de
news: 4605462f$0$6655$

soit le fragment de code suivant :

-------------------------------
struct mastruct {
unsigned int start,stop;
};


static int s_addrcmp_for_qsort(const void *a,const void *b )
{
const struct mastruct *line_a=(const struct mastruct *)a,
*line_b=(const struct mastruct *)b;
unsigned int result;


result= ((line_a->start)>>2) - ((line_b->start)>>2);

return result;
}

-------------------------

je compile en -Wall -Wextra, etc... avec un gcc 4.0.2, et celui ci
se
fache en me disant :
warning: cast discards qualifiers from pointer target type
sur la ligne : result= ((line_a->start)>>2) - ((line_b->start)>>2);
Si quelqu'un pouvait me dire ce que je fais de mal, je lui en serais
éternellement reconnaissant....

TM.


Avatar
Truc Muche
AG wrote:
soit tu appelles toujours la fonction s_addrcmp_for_qsort() avec,
comme argument, des struct mastruct. Auquel cas je ne vois pas
l'intérêt d'utiliser les types const void * en argument de fonction.
cette fonction est prototypée suivant un modele standart pour qsort:

son adresse est passée en argument lors de l'appel a qsort. Pour
simplifier, on va dire que son format est fixé.

Soit tu l'utilises sur des types qui ne sont pas des struct mastruct,
et là tu risques d'avoir des problèmes, car à priori, rien ne garanti
que la représentation mémoire de ta structure soit la même que celle
des autres types sur lesquel tu l'appliques. En particulier, il
pourrait y avoir des bits de padding entre tes deux unsigned int, ce
qui causerait des problèmes.
J'ai oublié de préciser que ce code fonctionne sous unix (freebsd, mac

osX) et probablement d'autres unix plus connus; où je n'ai jamais vu de
padding entre des ints: sizeof(mastruct)=8 en i386 et amd64.. Pour moi,
tu ne peux avoir de padding que dans le cas où tu utilise des type dont
la taille est plus petite que la largeur du bus (short, char en tableau
dont la taille n'est pas un multiple de sizeof(int)).
Ou alors quelque chose m'a échappé dans ta remarque.

Ceci dit, j'ai cette erreur de gcc uniquement quand je recompile en 64
bits sur un athlon (système et compilateur natifs 64 bits).

A+ TM.

Avatar
Pierre Maurette
soit le fragment de code suivant :

-------------------------------
struct mastruct {
unsigned int start,stop;
};


static int s_addrcmp_for_qsort(const void *a,const void *b )
{
const struct mastruct *line_a=(const struct mastruct *)a,
*line_b=(const struct mastruct *)b;
unsigned int result;


result= ((line_a->start)>>2) - ((line_b->start)>>2);

return result;
}

-------------------------

je compile en -Wall -Wextra, etc... avec un gcc 4.0.2, et celui ci se
fache en me disant :
warning: cast discards qualifiers from pointer target type
sur la ligne : result= ((line_a->start)>>2) - ((line_b->start)>>2);
Si quelqu'un pouvait me dire ce que je fais de mal, je lui en serais
éternellement reconnaissant....


Je ne reproduis pas votre warning, mais je n'ai pas exactement la même
version de gcc. Il me semble avoir un jour lu un truc à ce sujet, pas
nécessairement qu'il s'agit d'un bug (et encore) mais qu'il serait très
peu explicite danbs sa rédaction, voire trompeur.

Le décalage est une division par 4, en revanche je ne vois pas trop ce
que vous voulez faire en déclarant result en unsigned. Ne serait-ce pas
une erreur ?

Pour la fonction compar de qsort, je préfère la prototyper avec le type
pour lequel elle est écrite:

int s_addrcmp(const struct mastruct *a, const struct mastruct *b )
{
return ((a->start)>>2) - ((b->start)>>2);
}

(Dans l'hypothèse où j'ai compris votre but, ce qui n'est pas certain.
et >>2 ou /4, c'est kif)

Vous pouvez appeler la fonction telle quelle, ou expliciter les casts,
mais je pense que ça ne s'applique vraiment qu'à C++:

typedef int (*compar_for_qsort)(const void *, const void *);
...
compar_for_qsort s_addrcmp_for_qsort = (compar_for_qsort) s_addrcmp;

Voyez après ça si ça gueule toujours...

--
Pierre Maurette

Avatar
Pierre Maurette
Je ne saurais pas dire pourquoi gcc gueule. Par contre, je sais que ce que tu
fais est dangereux. Peut être est-ce pour cela que gcc émet un warning :

soit tu appelles toujours la fonction s_addrcmp_for_qsort() avec, comme
argument, des struct mastruct. Auquel cas je ne vois pas l'intérêt d'utiliser
les types const void * en argument de fonction. Soit tu l'utilises sur des
types qui ne sont pas des struct mastruct, et là tu risques d'avoir des
problèmes, car à priori, rien ne garanti que la représentation mémoire de ta
structure soit la même que celle des autres types sur lesquel tu l'appliques.
En particulier, il pourrait y avoir des bits de padding entre tes deux
unsigned int, ce qui causerait des problèmes. Il existe une option gcc pour
compiler sans bits de padding dans les structures.


Notez qu'en l'espèce le padding ne peut gêner et que la norme
permettrait d'écrire simplement:

static int s_addrcmp_for_qsort(const void *a,const void *b )
{
return (*(int*)a)/4 - (*(int*)b)/4;
}

De là à dire que c'est une bonne pratique... Tant qu'à faire:

static int s_addrcmp_for_qsort(const void *a,const void *b)
{
return (*(int*)(a + offsetof(struct mastruct, start)))/4
- (*(int*)(b + offsetof(struct mastruct, start)))/4;
}

qui donnera la même chose après le passage du préprocesseur.

--
Pierre Maurette

Avatar
Antoine Leca
En news:4605462f$0$6655$, Truc Muche va escriure:
struct mastruct { unsigned int start,stop; };

static int s_addrcmp_for_qsort(const void *a,const void *b ) {
const struct mastruct *line_a=(const struct mastruct *)a,
*line_b=(const struct mastruct *)b;
unsigned result=(line_a->start>>2) - (line_b->start>>2);
warning: cast discards qualifiers from pointer target type
sur la ligne : result= ((line_a->start)>>2) - ((line_b->start)>>2);
Si quelqu'un pouvait me dire ce que je fais de mal,


Je ne sais pas si c'est la raison de l'avertissement (extrêmement trompeur
ÀMHA si c'est bien le cas), mais il y a un souci dans la logique de ton code
:

a->start est non signé, >>2 il reste toujours non signé, b->start idem, la
différence est donc non signée (si b->start est plus grand que a->start, le
résultat est une valeur très grande genre 0xFFFFFF??, qui sera sur x86-64
étendue _à zéro_ sur 64 bits), et quand la fonction renvoit un entier signé
tu as un possible cas de débordement entier.

En gros, c'est l'exemple typique de raisons pour lesquelles on recommande en
C d'utiliser des signed int pour des quantités comme start ou stop. Ici on
peut contourner avec un transtypage du résultat du décalage, mais cela
rajoute encore des couches de trantypages et des parenthèses et cela
obscurcit (ÀMHA) le code.


Antoine

Avatar
Truc Muche
Antoine Leca wrote:
En news:4605462f$0$6655$, Truc Muche va escriure:
struct mastruct { unsigned int start,stop; };

static int s_addrcmp_for_qsort(const void *a,const void *b ) {
const struct mastruct *line_a=(const struct mastruct *)a,
*line_b=(const struct mastruct *)b;
unsigned result=(line_a->start>>2) - (line_b->start>>2);
warning: cast discards qualifiers from pointer target type
sur la ligne : result= ((line_a->start)>>2) - ((line_b->start)>>2);
Si quelqu'un pouvait me dire ce que je fais de mal,


Je ne sais pas si c'est la raison de l'avertissement (extrêmement trompeur
ÀMHA si c'est bien le cas),
Après de nombreux tests, ce warning est provoqué par -Wcast-qual.

D'après le man:
-Wcast-qual:
Warn whenever a pointer is cast so as to remove a type qualifier
from the target type. For example, warn if a "const char *" is
cast to an ordinary "char *".
Ce que je comprend dans les grandes lignes, mais que je n'arrive
pas a satisfaire gentillement a coup de cast...

mais il y a un souci dans la logique de ton code :

a->start est non signé, >>2 il reste toujours non signé, b->start idem, la
différence est donc non signée (si b->start est plus grand que a->start, le
résultat est une valeur très grande genre 0xFFFFFF??, qui sera sur x86-64
étendue _à zéro_ sur 64 bits), et quand la fonction renvoit un entier signé
tu as un possible cas de débordement entier.

En gros, c'est l'exemple typique de raisons pour lesquelles on recommande en
C d'utiliser des signed int pour des quantités comme start ou stop. Ici on
peut contourner avec un transtypage du résultat du décalage, mais cela
rajoute encore des couches de trantypages et des parenthèses et cela
obscurcit (ÀMHA) le code.


en fait, l'ensemble de ce source (non montré ici) lit des fichiers
contenant des listes d'adresses ip (V4) et les trie (avec qsort et cette
fonction) pour ensuite fusionner les plages qui se chevauchent .
Les adresses ip sont préalablement mise en format "unsigned int" natif
du processeur (uint32), pour les manipuler plus simplement.
Le shift de 2 permet justement de m'affranchir des débordements
d'entiers 32 bits lors de la soustraction et du retour de "result".
Ce n'est pas très académique, mais dans mon cas de figure où les
adresses ip ont toujours au moins en /24 (les derniers 8 bits sont
nulls), cela fonctionne. Mais c'est vrai que ce n'est pas très élégant.

TM.

PS: sur toutes les machines 64 bits avec lesquelle j'ai travaillé
(sparc64, x86-64), un int était toujours en 32 bits (LP64):
le fait d'être sur une archi 64 bits n'a pas d'influence là.
( http://www.unix.org/whitepapers/64bit.html ).


Avatar
Antoine Leca
En news:4609436e$0$6421$, Truc Muche va escriure:
Le shift de 2 permet justement de m'affranchir des débordements
d'entiers 32 bits lors de la soustraction et du retour de "result".


Cela supprime le problème pratique (et un commentaire pourrait éclairer
utilisement le lecteur), ce qui permet effectivement de faire marcher...
tant que le processeur ne piège pas les débordements lors de la conversion
unsigned vers signed (au moment du return).
Sinon (piège sur overflow) c'est SIGFPE ou équivalent.

Pourquoi refuser de mettre les transtypages vers (signed) pour chacun des
deux décalages ?


PS: sur toutes les machines 64 bits avec lesquelle j'ai travaillé
(sparc64, x86-64), un int était toujours en 32 bits (LP64):


Et sur un Cray, il est sur 64 bits (ILP64). Et alors?

le fait d'être sur une archi 64 bits n'a pas d'influence là.


Bin si, justement en LP64 : cela dépend comment l'architecture va
implémenter la manipulation des quantités 32 bits non signés (si elle étend
le signe ou préserve la valeur) et par ailleurs comment elle fait la
conversion unsigned->signed. J'ai mentionné la conversion que faisait x86-64
dans le premier cas, car le processeur ne laisse pas vraiment le choix ;
dans le second cas, cela dépend comment le compilateur implémente la
conversion, et je pense qu'il doit être possible avec x86-64 d'implémenter
une vérification de débordement à ce niveau (d'autant plus que les adresses
sur x86-64 ont des contraintes, 0xAAAAAAAAAAAAAAAA fait flasher le
processeur si elle est déréférencée)


Antoine

Avatar
-ed-
On 24 mar, 17:39, Truc Muche wrote:
soit le fragment de code suivant :

-------------------------------
struct mastruct {
unsigned int start,stop;

};

static int s_addrcmp_for_qsort(const void *a,const void *b )
{
const struct mastruct *line_a=(const struct mastruct *)a,
*line_b=(const struct mastruct *)b;
unsigned int result;

result= ((line_a->start)>>2) - ((line_b->start)>>2);

return result;

}

-------------------------

je compile en -Wall -Wextra, etc... avec un gcc 4.0.2, et celui ci se
fache en me disant :
warning: cast discards qualifiers from pointer target type
sur la ligne : result= ((line_a->start)>>2) - ((line_b->start)>>2);
Si quelqu'un pouvait me dire ce que je fais de mal, je lui en serais
éternellement reconnaissant....

TM.


Je ferais comme ceci :

struct mastruct
{
unsigned start;
unsigned stop;
};

static int s_addrcmp_for_qsort (const void *a, const void *b)
{
const struct mastruct *line_a = a;
const struct mastruct *line_b = b;

return (line_a->start >> 2) - (line_b->start >> 2);
}

En effet, une différence peut être < 0, ce qui est logique vu le type
retourné par la fonction de comparaison de qsort().

Avatar
-ed-
On 26 mar, 17:51, "AG" wrote:
Je ne saurais pas dire pourquoi gcc gueule. Par contre, je sais que ce
que tu fais est dangereux. Peut être est-ce pour cela que gcc émet un
warning :

soit tu appelles toujours la fonction s_addrcmp_for_qsort() avec,
comme argument, des struct mastruct. Auquel cas je ne vois pas
l'intérêt d'utiliser les types const void * en argument de fonction.


Visiblement, tu ne sais pas de quoi tu parles. Renseigne toi sur la
fonction qsort() et son callback de comparaison...

Avatar
Eric Levenez
Le 4/04/07 9:49, dans ,
« -ed- » a écrit :

Alors de retour pour mettre de l'ordre dans ce NG ? :-)

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.