426 votes

MIN et MAX en C

Où sont MIN y MAX définie en C, si elle existe ?

Quelle est la meilleure façon de les implémenter, de manière aussi générique et sûre que possible ? (De préférence, extensions de compilateurs ou buildins pour les compilateurs grand public).

3 votes

Quelqu'un peut-il vérifier ce et dire si c'est une macro ou une fonction ? J'entends par là que, dans la ligne min(x++, y++) , x et y sont incrémentés une ou deux fois si j'utilise ceci min .

528voto

David Titarenco Points 17148

Où sont MIN y MAX définie en C, si elle existe ?

Ils ne le sont pas.

Quelle est la meilleure façon de les implémenter, de la manière la plus générique et la plus sûre possible (extensions de compilateurs/compléments pour les compilateurs courants de préférence) ?

En tant que fonctions. Je n'utiliserais pas de macros comme #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) surtout si vous envisagez de déployer votre code. Soit vous écrivez votre propre code, soit vous utilisez quelque chose comme le standard fmax o fmin ou corrigez la macro en utilisant Le type de GCC (vous bénéficiez également d'une prime de sécurité type) dans un centre d'hébergement. Expression de la déclaration GCC :

 #define max(a,b) \
   ({ __typeof__ (a) _a = (a); \
       __typeof__ (b) _b = (b); \
     _a > _b ? _a : _b; })

Tout le monde dit "oh, je connais la double évaluation, ce n'est pas un problème" et quelques mois plus tard, vous devrez déboguer les problèmes les plus stupides pendant des heures.

Notez l'utilisation de __typeof__ au lieu de typeof :

Si vous écrivez un fichier d'en-tête qui doit fonctionner lorsqu'il est inclus dans des programmes ISO C ISO, écrivez __typeof__ au lieu de typeof .

88 votes

Vous savez, ce serait bien pratique si gcc avait un avertissement du genre : warning: expression with side-effects multiply evaluated by macro au point d'utilisation...

32 votes

@caf : cela ne nécessiterait-il pas que le préprocesseur ait une connaissance plus complexe de la syntaxe C ?

2 votes

@dreamlax : Je pensais que le préprocesseur pourrait laisser des annotations au point de chaque expansion de macro lorsqu'un paramètre est utilisé plus d'une fois, que le compilateur pourrait alors utiliser.

121voto

Mikel Points 10000

Il est également fourni dans les versions GNU libc (Linux) et FreeBSD de sys/param.h et a la définition fournie par dreamlax.


Sur Debian :

$ uname -sr
Linux 2.6.11

$ cat /etc/debian_version
5.0.2

$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

$ head -n 2 /usr/include/sys/param.h | grep GNU
This file is part of the GNU C Library.

Sur FreeBSD :

$ uname -sr
FreeBSD 5.5-STABLE

$ egrep 'MIN\(|MAX\(' /usr/include/sys/param.h
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

Les dépôts de sources sont ici :

0 votes

J'ai ajouté les définitions des systèmes auxquels j'ai accès dans ma réponse ci-dessus (le champ de commentaire n'accepte pas le formatage, pour autant que je sache). Je vais essayer de trouver les liens vers les dépôts de sources FreeBSD/Linux/glibc.

0 votes

+1. Très bien. Fonctionne pour openSUSE/Linux 3.1.0-1.2-desktop / gcc version 4.6.2 (SUSE Linux) aussi. :) Dommage que ce ne soit pas portable.

0 votes

Fonctionne aussi sur Cygwin.

117voto

dan04 Points 33306

Il y a un std::min y std::max en C++, mais AFAIK, il n'y a pas d'équivalent dans la bibliothèque standard du C. Vous pouvez les définir vous-même avec des macros comme

#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))

Mais cela pose des problèmes si vous écrivez quelque chose comme MAX(++a, ++b) .

13 votes

Pourquoi mettre trop de parenthèses ? ?? J'ai trouvé un quiz où ils ont dit #define MIN(A, B) ((A < B) ? A : B) n'est pas un moyen flexible, pourquoi ?

115 votes

@Makouda : Les parenthèses supplémentaires dans les macros permettent d'éviter les problèmes de précédence des opérateurs. Par exemple, considérez #define MULT(x, y) x * y . Ensuite, MULT(a + b, a + b) s'étend à a + b * a + b qui se traduit par a + (b * a) + b en raison de la préséance. Ce n'est probablement pas ce que le programmeur voulait.

1 votes

Qui n'est pas nécessaire quand ? : a la plus petite priorité de toute façon

24voto

dreamlax Points 47152

Je ne pense pas qu'il s'agisse de macros standardisées. Il existe déjà des fonctions standardisées pour la virgule flottante, fmax y fmin (et fmaxf pour les flotteurs, et fmaxl pour les doubles longs).

Vous pouvez les mettre en œuvre sous forme de macros, à condition d'être conscient des problèmes d'effets secondaires et de double évaluation.

#define MAX(a,b) ((a) > (b) ? a : b)
#define MIN(a,b) ((a) < (b) ? a : b)

Dans la plupart des cas, vous pouvez laisser au compilateur le soin de déterminer ce que vous essayez de faire et de l'optimiser du mieux qu'il peut. Bien que cela pose des problèmes lorsqu'il est utilisé comme MAX(i++, j++) Je doute qu'il soit nécessaire de vérifier le maximum de valeurs incrémentées en une seule fois. Incrémentez d'abord, puis vérifiez.

0 votes

Cette réponse devrait être privilégiée car il existe clairement des fonctions min et max dans la bibliothèque mathématique : cplusplus.com/reference/cmath/fmax

0 votes

@imranal De quoi parlez-vous exactement ? Le site mise en œuvre code de ces bibliothèques ? Mais ce code n'est pas exposé En d'autres termes, ils ne le placent pas dans l'interface de la bibliothèque, qui est potentiellement dangereuse.

1 votes

@Antonio Je pense que vous utilisez des définitions incorrectes de "exposé" et "interface". L'interface d'une bibliothèque c est constituée des variables, types, macros et déclarations de fonctions externalisés dans un fichier d'en-tête ; fmin/fmax sont déclarés dans le fichier d'en-tête, on dit donc qu'ils sont exposés. Je ne suis pas sûr de ce que vous considérez comme dangereux.

12voto

Matt Joiner Points 29194

J'ai écrit ceci version qui fonctionne pour MSVC, GCC, C et C++.

#if defined(__cplusplus) && !defined(__GNUC__)
#   include <algorithm>
#   define MIN std::min
#   define MAX std::max
//#   define TMIN(T, a, b) std::min<T>(a, b)
//#   define TMAX(T, a, b) std::max<T>(a, b)
#else
#       define _CHOOSE2(binoper, lexpr, lvar, rexpr, rvar) \
                ({ \
                        decltype(lexpr) lvar = (lexpr); \
                        decltype(rexpr) rvar = (rexpr); \
                        lvar binoper rvar ? lvar : rvar; \
                })
#       define _CHOOSE_VAR2(prefix, unique) prefix##unique
#       define _CHOOSE_VAR(prefix, unique) _CHOOSE_VAR2(prefix, unique)
#       define _CHOOSE(binoper, lexpr, rexpr) \
                _CHOOSE2( \
                        binoper, \
                        lexpr, _CHOOSE_VAR(_left, __COUNTER__), \
                        rexpr, _CHOOSE_VAR(_right, __COUNTER__) \
                )
#       define MIN(a, b) _CHOOSE(<, a, b)
#       define MAX(a, b) _CHOOSE(>, a, b)
#endif

3 votes

J'ai voté pour, mais les identifiants commençant par un trait de soulignement suivi d'une lettre majuscule sont réservés.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X