Comparaîson étrange

Le
Thomas Nemeth
Bonjour à tous et excusez-moi de vous sortir de vos
comparaîsons Python/Ruby/Java/whatever ;)

Je viens de lire un article très intéressant à propos de la conception
d'API (http://ozlabs.org/~rusty/index.cgi/tech/2008-03-30.html pour
ceux que ça intéresserait) mettant des mots sur ce qu'on pratique et
voit régulièrement. J'y suis tombé sur un exemple qui me laisse
perplexe :

8<
The classic of this school is the Linux kernel min() and max() macros,
which use two GCC extensions: a statement expression which allows the
whole statement to be treated by the caller as a single expression, and
typeof which lets us declare a temporary variable of same type as
another:
/*
* min()/max() macros that also do
* strict type-checking.. See the
* "unnecessary" pointer comparison.
*/
#define min(x,y) ({
typeof(x) _x = (x);
typeof(y) _y = (y);
(void) (&_x == &_y);
_x < _y ? _x : _y; })

Since a common error in C is to compare signed vs unsigned types and
expect a signed result, this macro insists that both types be identical.
8<

Cette macro me pose 2 problèmes dont j'ai déduit la réponse à l'un
d'eux.

Tout d'abord, comme pointé dans le commentaire, pourquoi comparer
les _adresses_ des 2 variables temporaires ? Je comprends qu'on puisse
vouloir faire qu'une comparaîson échoue si 2 types sont différents
mais pour les adresses, je ne comprends pas. Un effet de bord du
compilateur ?

Enfin, c'est la forme que prend cette macro : ({}). C'est une
construction que je n'avais pas vu (ou à laquelle je n'avais pas
prêté attention) avant. Les accolades sont, bien entendu, nécessaire
pour créer un bloc avec des variables dedans et les parenthèses sont
là pour "créer" une expression qui retournera une valeur. J'en
conclu que, la valeur retournée devant être celle de l'expression
c?a:b, le bloc "retournait" cette expression.
Est-ce un effet de bord du compilateur ?
Comment un bloc sans "return" peut-il renvoyer une valeur ?
Est-ce utilisable avec n'importe quelle autre expression ?


Thomas.
Questions / Réponses high-tech
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Jean-Marc Bourguet
Le #1983511
Thomas Nemeth
---8<------------------------------------
The classic of this school is the Linux kernel min() and max() macros,
which use two GCC extensions: a statement expression which allows the
whole statement to be treated by the caller as a single expression, and
typeof which lets us declare a temporary variable of same type as
another:
/*
* min()/max() macros that also do
* strict type-checking.. See the
* "unnecessary" pointer comparison.
*/
#define min(x,y) ({
typeof(x) _x = (x);
typeof(y) _y = (y);
(void) (&_x == &_y);
_x < _y ? _x : _y; })

Since a common error in C is to compare signed vs unsigned types and
expect a signed result, this macro insists that both types be identical.
---8<------------------------------------

Cette macro me pose 2 problèmes dont j'ai déduit la réponse à l'un
d'eux.

Tout d'abord, comme pointé dans le commentaire, pourquoi comparer
les _adresses_ des 2 variables temporaires ? Je comprends qu'on puisse
vouloir faire qu'une comparaîson échoue si 2 types sont différents
mais pour les adresses, je ne comprends pas. Un effet de bord du
compilateur ?


Plutot que de comparer les types, la macro compare des variables de type
pointeurs sur les types qu'on veut comparer. Si les types ne sont pas les
memes, la comparaison des pointeurs sera invalides.

typeof est une des extensions de gcc dont il est question.

Enfin, c'est la forme que prend cette macro : ({...}). C'est une
construction que je n'avais pas vu (ou à laquelle je n'avais pas
prêté attention) avant.


C'est l'autre extension de gcc.

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

Thomas Nemeth
Le #1985021
Jean-Marc Bourguet a tapoté :

Thomas Nemeth
---8<------------------------------------
/*
* min()/max() macros that also do
* strict type-checking.. See the
* "unnecessary" pointer comparison.
*/
#define min(x,y) ({
typeof(x) _x = (x);
typeof(y) _y = (y);
(void) (&_x == &_y);
_x < _y ? _x : _y; })
identical. ---8<------------------------------------

Cette macro me pose 2 problèmes dont j'ai déduit la réponse à l'un
d'eux.

Tout d'abord, comme pointé dans le commentaire, pourquoi comparer
les _adresses_ des 2 variables temporaires ? Je comprends qu'on
puisse vouloir faire qu'une comparaîson échoue si 2 types sont
différents mais pour les adresses, je ne comprends pas. Un effet de
bord du compilateur ?


Plutot que de comparer les types, la macro compare des variables de type
pointeurs sur les types qu'on veut comparer. Si les types ne sont pas
les memes, la comparaison des pointeurs sera invalides.


Tu veux dire que le fait de _vouloir_ comparer des pointeurs sur
des données de types différents lève une erreur, je suppose ? Car
il me semble que des pointeurs sur des données de même type sont
toujours différents du moment qu'ils ne pointent pas sur les mêmes
données...

Me trompe-je ?

Merci pour tes infos.

Thomas.


Alain
Le #1994301
On Tue, 01 Apr 2008 12:04:48 +0200
Thomas Nemeth wrote:

[...]
Comment un bloc sans "return" peut-il renvoyer une valeur ?
Est-ce utilisable avec n'importe quelle autre expression ?


il ne renvoie pas, il a une valeur, c'est ce qui fait marcher:

a = (b = c);

et

if (a = b) {
[...]
}

on peut apres imaginer encore tout plein de choses bien gores =)

--
Alain

Thomas Nemeth
Le #2043111
Alain a tapoté :

On Tue, 01 Apr 2008 12:04:48 +0200
Thomas Nemeth wrote:

[...]
Comment un bloc sans "return" peut-il renvoyer une valeur ?
Est-ce utilisable avec n'importe quelle autre expression ?


il ne renvoie pas, il a une valeur, c'est ce qui fait marcher:
a = (b = c);


Argh. Ok.


et
if (a = b) {


Qui ne devrait jamais être utilisé. C'est une trop grande source
d'erreurs.


on peut apres imaginer encore tout plein de choses bien gores =)


Tu m'étonnes ! Pour moi c'est philosophiquement dérangeant :) Mais
je conçois maintenant comment ça marche.

Merci.


Thomas.


Alain
Le #2043101
On Wed, 02 Apr 2008 09:47:26 +0200
Thomas Nemeth wrote:

Alain a tapoté :

[...]

et
if (a = b) {


Qui ne devrait jamais être utilisé. C'est une trop grande source
d'erreurs.


en fait on voit tres souvent une variante:

if (a = b()) {
[...]
}

pour assigner et tester en meme temps la valeur de retour, mais bon
c'est pas mieux ;-)

--
Alain


Pierre Maurette
Le #2045961
On Wed, 02 Apr 2008 09:47:26 +0200
Thomas Nemeth wrote:

Alain a tapoté :

[...]

et
if (a = b) {


Qui ne devrait jamais être utilisé. C'est une trop grande source
d'erreurs.


en fait on voit tres souvent une variante:

if (a = b()) {
[...]
}

pour assigner et tester en meme temps la valeur de retour, mais bon
c'est pas mieux ;-)


Les compilateurs ayant en général la gentillesse d'avertir, il faut lui
expliquer, ainsi qu'au relecteur, son intention. Ça vaut largement un
commentaire /* affectation simultanée */:

if ((x = f()) != 0){
/* ... */
}

if ((x = y) != 0){
/* ... */
}

--
Pierre Maurette



Erwan David
Le #2050341
Alain
en fait on voit tres souvent une variante:

if (a = b()) {
[...]
}

pour assigner et tester en meme temps la valeur de retour, mais bon
c'est pas mieux ;-)


if((a = f()) == val)
{
[....]
}

est assezlisible quand même.

--
Le travail n'est pas une bonne chose. Si ça l'était,
les riches l'auraient accaparé

Marc Boyer
Le #2052871
On 2008-04-02, Alain
On Wed, 02 Apr 2008 09:47:26 +0200
Thomas Nemeth wrote:

Alain a tapoté :

[...]

et
if (a = b) {


Qui ne devrait jamais être utilisé. C'est une trop grande source
d'erreurs.


en fait on voit tres souvent une variante:

if (a = b()) {
[...]
}

pour assigner et tester en meme temps la valeur de retour, mais bon
c'est pas mieux ;-)


C'est pas mieux, et surtout, ça n'est pas plus lisible que
a= b();
if (a){...
}

Par contre, c'est très utile pour résoudre le problème de
la boucle et demi.

int c;
while( (c= getchar()) != EOF){
...
}

qui, si on ne s'autorise pas cette syntaxe, devient un rien
plus pénible à faire
do {
c= getchar();
if (c != EOF) {
...
}
while ( c!= EOF );


Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)



Publicité
Poster une réponse
Anonyme