MIN et MAX en C

301

Où sont MINet MAXdéfinis en C, le cas échéant?

Quelle est la meilleure façon de les implémenter, de manière aussi générique et sécurisée que possible? (Les extensions / buildins du compilateur pour les compilateurs traditionnels sont préférés.)

Matt Joiner
la source

Réponses:

392

Où sont MINet MAXdéfinis en C, le cas échéant?

Ils ne le sont pas.

Quelle est la meilleure façon de les implémenter, de manière aussi générique et sécurisée que possible (extensions / compilations de compilateur pour les compilateurs traditionnels préférés).

Comme fonctions. Je n'utiliserais pas de macros comme #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)), surtout si vous prévoyez de déployer votre code. Soit écrivez le vôtre, utilisez quelque chose comme standard fmaxou fmin, ou corrigez la macro en utilisant typeof de GCC (vous obtenez également un bonus de sécurité de type) dans une expression d'instruction 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 déboguerez 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 les programmes ISO C, écrivez à la __typeof__place de typeof.

David Titarenco
la source
68
Vous savez, ce serait très pratique si gcc avait un avertissement du type: warning: expression with side-effects multiply evaluated by macroau point d'utilisation ...
caf
23
@caf: cela ne nécessiterait-il pas que le préprocesseur ait une connaissance plus compliquée de la syntaxe C?
dreamlax
3
Après avoir essayé de comprendre, je ne pense pas qu'il soit possible de le faire dans VC ++, mais votre mieux est d'essayer de jouer avec le nouveau decltypemot clé MSVC ++ 2010 - mais même ainsi, Visual Studio ne peut pas faire d'instructions composées dans les macros (et decltypeest de toute façon C ++), c'est-à-dire la ({ ... })syntaxe de GCC, donc je suis sûr que ce n'est pas possible, de toute façon. Je n'ai pas regardé d'autres compilateurs concernant ce problème, désolé Luther: S
David Titarenco
7
@dreamlax J'ai vu une fois un cas où quelqu'un avait fait MAX(someUpperBound, someRandomFunction())pour limiter une valeur aléatoire à une limite supérieure. C'était une idée terrible, mais cela n'a pas fonctionné non plus, car celui MAXqu'il utilisait avait le problème de la double évaluation, alors il s'est retrouvé avec un nombre aléatoire différent de celui qui avait été initialement évalué.
Zev Eisenberg
8
@Soumen Par exemple, si vous appelez MIN(x++, y++)le préprocesseur, le code suivant sera généré (((x++) < (y++)) ? (x++) : (y++)). Donc, xet ysera incrémenté deux fois.
Antonio
91

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 référentiels sources sont ici:

Mikel
la source
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). J'essaierai de trouver les liens vers le dépôt source FreeBSD / Linux / glibc.
Mikel du
+1. Très agréable. 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.
Jack
Fonctionne également sur Cygwin.
CMCDragonkai
1
Attendez un moment. Cela n'empêche pas la double évaluation, n'est-ce pas? : 3
user1857492
76

Il y a un std::minet std::maxen C ++, mais AFAIK, il n'y a pas d'équivalent dans la bibliothèque standard 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).

dan04
la source
10
pourquoi mettre trop de parenthèses ??? J'ai trouvé un quiz où ils ont dit que ce #define MIN(A, B) ((A < B) ? A : B)n'était pas un moyen flexible, pourquoi ???
79
@Makouda: des parenthèses supplémentaires dans les macros permettent d'éviter les problèmes de priorité des opérateurs. Par exemple, réfléchissez #define MULT(x, y) x * y. Se MULT(a + b, a + b)développe ensuite en a + b * a + b, qui est analysé en a + (b * a) + braison de la priorité. Ce n'est pas ce que le programmeur voulait probablement.
dan04
qui n'est pas nécessaire quand?: a la priorité la plus faible de toute façon
Winger Sendon
1
@WingerSendon: Ce n'est pas le cas; l'opérateur de virgule le fait.
dan04
24

Évitez les extensions de compilateur non standard et implémentez-la en tant que macro de type complètement sécurisé dans la norme C pure (ISO 9899: 2011).

Solution

#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))

#define ENSURE_int(i)   _Generic((i), int:   (i))
#define ENSURE_float(f) _Generic((f), float: (f))


#define MAX(type, x, y) \
  (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))

Usage

MAX(int, 2, 3)

Explication

La macro MAX crée une autre macro basée sur le typeparamètre. Cette macro de contrôle, si elle est implémentée pour le type donné, est utilisée pour vérifier que les deux paramètres sont du type correct. Si latype n'est pas pris en charge, il y aura une erreur de compilation.

Si x ou y n'est pas du type correct, il y aura une erreur de compilation dans le ENSURE_ macros. D'autres macros de ce type peuvent être ajoutées si plusieurs types sont pris en charge. J'ai supposé que seuls les types arithmétiques (entiers, flottants, pointeurs, etc.) seront utilisés et non les structures ou les tableaux, etc.

Si tous les types sont corrects, la macro GENERIC_MAX sera appelée. Des parenthèses supplémentaires sont nécessaires autour de chaque paramètre de macro, comme la précaution standard habituelle lors de l'écriture des macros C.

Ensuite, il y a les problèmes habituels avec les promotions de type implicites en C. L' ?:opérateur équilibre les 2e et 3e opérandes l'un par rapport à l'autre. Par exemple, le résultat de GENERIC_MAX(my_char1, my_char2)serait un int. Pour empêcher la macro d'effectuer de telles promotions de type potentiellement dangereuses, une conversion de type final vers le type prévu a été utilisée.

Raisonnement

Nous voulons que les deux paramètres de la macro soient du même type. Si l'un d'eux est d'un type différent, la macro n'est plus de type sécurisé, car un opérateur comme?: ci produira des promotions de type implicites. Et parce que c'est le cas, nous devons également toujours restituer le résultat final au type prévu, comme expliqué ci-dessus.

Une macro avec un seul paramètre aurait pu être écrite de manière beaucoup plus simple. Mais avec 2 paramètres ou plus, il est nécessaire d'inclure un paramètre de type supplémentaire. Parce que quelque chose comme ça est malheureusement impossible:

// this won't work
#define MAX(x, y)                                  \
  _Generic((x),                                    \
           int: GENERIC_MAX(x, ENSURE_int(y))      \
           float: GENERIC_MAX(x, ENSURE_float(y))  \
          )

Le problème est que si la macro ci-dessus est appelée comme MAX(1, 2)avec deux int, elle essaiera toujours de macro-développer tous les scénarios possibles de la _Genericliste d'association. Ainsi, la ENSURE_floatmacro sera également développée, même si elle n'est pas pertinente pour int. Et puisque cette macro ne contient intentionnellement que le floattype, le code ne sera pas compilé.

Pour résoudre ce problème, j'ai plutôt créé le nom de la macro lors de la phase de pré-processeur, avec l'opérateur ##, afin qu'aucune macro ne soit accidentellement développée.

Exemples

#include <stdio.h>

#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))

#define ENSURE_int(i)   _Generic((i), int:   (i))
#define ENSURE_float(f) _Generic((f), float: (f))


#define MAX(type, x, y) \
  (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))

int main (void)
{
  int    ia = 1,    ib = 2;
  float  fa = 3.0f, fb = 4.0f;
  double da = 5.0,  db = 6.0;

  printf("%d\n", MAX(int,   ia, ib)); // ok
  printf("%f\n", MAX(float, fa, fb)); // ok

//printf("%d\n", MAX(int,   ia, fa));  compiler error, one of the types is wrong
//printf("%f\n", MAX(float, fa, ib));  compiler error, one of the types is wrong
//printf("%f\n", MAX(double, fa, fb)); compiler error, the specified type is wrong
//printf("%f\n", MAX(float, da, db));  compiler error, one of the types is wrong

//printf("%d\n", MAX(unsigned int, ia, ib)); // wont get away with this either
//printf("%d\n", MAX(int32_t, ia, ib)); // wont get away with this either
  return 0;
}
Lundin
la source
Soit dit GENERIC_MAXen passant, cette macro est une mauvaise idée, il suffit de chercher GENERIC_MAX(var++, 7)pourquoi :-) De nos jours (en particulier avec les compilateurs fortement optimisés / en ligne), les macros devraient être reléguées aux formulaires simples uniquement. Les fonctions de type sont meilleures en tant que fonctions et celles de groupes de valeurs en tant qu'énumérations.
paxdiablo
21

Je ne pense pas que ce soient des macros standardisées. Il existe déjà des fonctions standardisées pour les virgules flottantes fmaxet fmin(et fmaxfpour les flottants et les fmaxllongs doubles).

Vous pouvez les implémenter sous forme de macros tant que vous êtes conscient des problèmes d'effets secondaires / 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 toujours nécessaire de vérifier le maximum de valeurs incrémentées en une seule fois. Incrémentez d'abord, puis vérifiez.

dreamlax
la source
Cela devrait être la réponse préférée car il y a clairement des fonctions min et max dans la bibliothèque mathématique: cplusplus.com/reference/cmath/fmax
imranal
@imranal De quoi parlez-vous exactement? Le code d' implémentation de ces bibliothèques? Mais ce code n'est pas exposé , c'est-à-dire qu'ils ne le placent pas dans l'interface de la bibliothèque, étant potentiellement dangereux.
Antonio
@Antonio Je pense que vous utilisez des définitions incorrectes de "exposé" et "interface". L'interface de la bibliothèque AC sont les variables, types, macros et déclarations de fonction externes dans un fichier d'en-tête; fmin / fmax sont déclarés dans le fichier d'en-tête, ils sont donc censés être exposés. Je ne suis pas sûr de ce que vous appelez dangereux.
rationalcoder
21

Il s'agit d'une réponse tardive, en raison d'un développement assez récent. Étant donné que l'OP a accepté la réponse qui repose sur une extension GCC (et clang) non portable typeof- ou __typeof__pour ISO C «propre» - il existe une meilleure solution à partir de gcc-4.9 .

#define max(x,y) ( \
    { __auto_type __x = (x); __auto_type __y = (y); \
      __x > __y ? __x : __y; })

L'avantage évident de cette extension est que chaque argument de macro n'est développé qu'une seule fois, contrairement à la __typeof__solution.

__auto_typeest une forme limitée de C ++ 11 auto. Il ne peut pas (ou ne devrait pas?) Être utilisé dans le code C ++, bien qu'il n'y ait aucune bonne raison de ne pas utiliser les capacités d'inférence de type supérieures autolorsque vous utilisez C ++ 11.

Cela dit, je suppose qu'il n'y a aucun problème à utiliser cette syntaxe lorsque la macro est incluse dans une extern "C" { ... }portée; par exemple, à partir d'un en-tête C. AFAIK, cette extension n'a pas trouvé son chemin info clang

Brett Hale
la source
Lié au commentaire de Brett Hale , a clangcommencé à prendre en charge __auto_typevers 2016 (voir patch ).
Lars
Félicitations pour avoir reconnu le problème des macros, mais je dirais quand même qu'une fonction serait probablement meilleure :-)
paxdiablo
@paxdiablo - Je suis d'accord, bien que la question ait la c-preprocessorbalise. Une fonction n'est pas garantie d'être alignée même avec ledit mot clé, à moins d'utiliser quelque chose comme l' __always_inline__attribut de gcc .
Brett Hale
11

J'ai écrit cette 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
Matt Joiner
la source
1
J'ai voté positivement mais les identifiants commençant par un trait de soulignement suivi d'une lettre majuscule sont réservés.
dreamlax
8

Si vous avez besoin de min / max pour éviter une branche coûteuse, vous ne devez pas utiliser l'opérateur ternaire, car il se compilera en un saut. Le lien ci-dessous décrit une méthode utile pour implémenter une fonction min / max sans branchement.

http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax

cib
la source
1
Si le compilateur est assez intelligent, il peut éviter la branche
Axel Gneiting
2
Si l'optimisation est activée, tous les compilateurs modernes émettront un mouvement conditionnel au lieu d'une branche dans la plupart des cas, il est donc inutile d'utiliser des hacks comme celui-ci.
Krzysztof Kosiński
2
Absolument vrai, je n'ai aucune idée de ce que je regardais à l'époque, ça fait un moment. Gcc et clang évitent les branches avec -O, à la fois sur x86 et armv7a.
cib
6

@David Titarenco l'a cloué ici , mais permettez-moi au moins de le nettoyer un peu pour le rendre joli, et de montrer à la fois min() et max() ensemble pour faciliter le copier-coller à partir d'ici. :)

Mise à jour du 25 avril 2020: j'ai également ajouté une section 3 pour montrer comment cela serait également fait avec les modèles C ++, comme une comparaison utile pour ceux qui apprennent à la fois le C et le C ++, ou qui passent de l'un à l'autre. J'ai fait de mon mieux pour être complet et factuel et correct pour faire de cette réponse une référence canonique à laquelle je pourrai revenir encore et encore, et j'espère que vous la trouverez aussi utile que moi.

1. L'ancienne méthode macro C:

Cette technique est couramment utilisée, bien respectée par ceux qui savent l'utiliser correctement, la façon "de facto" de faire les choses, et très bien à utiliser si elle est utilisée correctement, mais buggy (pensez: effet secondaire à double évaluation ) si vous jamais passer des expressions, y compris l'affectation des variables pour comparer:

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

2. La nouvelle et améliorée méthode gcc " expression statement ":

Cette technique évite les effets secondaires et les bogues "à double évaluation" ci-dessus et est donc considérée comme la manière GCC C supérieure, plus sûre et "plus moderne" de le faire. Attendez-vous à ce qu'il fonctionne avec les compilateurs gcc et clang, car clang est, par conception, compatible gcc (voir la note de clang au bas de cette réponse).

MAIS: Méfiez-vous toujours des effets "d' observation des variables ", car les expressions d'instructions sont apparemment alignées et n'ont donc PAS leur propre portée de variable locale!

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

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

Notez que dans les expressions d'instruction gcc, la dernière expression du bloc de code est ce qui est "renvoyé" à partir de l'expression, comme si elle avait été renvoyée par une fonction. La documentation de GCC le dit ainsi:

La dernière chose dans l'instruction composée doit être une expression suivie d'un point-virgule; la valeur de cette sous-expression sert de valeur à la construction entière. (Si vous utilisez un autre type d'instruction en dernier entre les accolades, la construction a le type void, et donc aucune valeur.)

3. La manière du modèle C ++:

C ++ Remarque: si vous utilisez C ++, les modèles sont probablement recommandés pour ce type de construction à la place, mais personnellement je n'aime pas les modèles et utiliserais probablement l'une des constructions ci-dessus en C ++, car j'utilise et préfère souvent les styles C en C ++ incorporé également.

Cette section a ajouté le 25 avril 2020:

J'ai fait une tonne de C ++ ces derniers mois, et la pression pour préférer les modèles aux macros, si possible, dans la communauté C ++ est assez forte. En conséquence, je me suis amélioré dans l'utilisation des modèles et je souhaite insérer ici les versions des modèles C ++ pour être complet et en faire une réponse plus canonique et approfondie.

Voici ce que base modèle de la fonction versions max()et min()pourraient ressembler en C ++:

template <typename T>
T max(T a, T b)
{
    return a > b ? a : b;
}

template <typename T>
T min(T a, T b)
{
    return a < b ? a : b;
}

Faites des lectures supplémentaires sur les modèles C ++ ici: Wikipedia: Template (C ++) .

Cependant, les deux max()et min()font déjà partie de la bibliothèque standard C ++, dans l'en- <algorithm>tête ( #include <algorithm>). Dans la bibliothèque standard C ++, ils sont définis légèrement différemment que je les ai ci-dessus. Les prototypes par défaut pour std::max<>()et std::min<>(), par exemple, en C ++ 14, en regardant leurs prototypes dans les liens cplusplus.com juste au-dessus, sont:

template <class T> 
constexpr const T& max(const T& a, const T& b);

template <class T> 
constexpr const T& min(const T& a, const T& b);

Notez que le mot - clé typenameest un alias class( de sorte que leur utilisation est identique si vous dites <typename T>ou <class T>), car il a été reconnu plus tard après l'invention de C ++ modèles, que le type de modèle peut être un type régulier ( int, float, etc.) au lieu de seulement un type de classe.

Ici, vous pouvez voir que les deux types d'entrée, ainsi que le type de retour, le sont const T&, ce qui signifie "référence constante au type T". Cela signifie que les paramètres d'entrée et la valeur de retour sont transmis par référence au lieu d'être transmis par valeur . Cela revient à passer par des pointeurs et est plus efficace pour les grands types, tels que les objets de classe. La constexprpartie de la fonction modifie la fonction elle - même et indique que la fonction doit pouvoir être évaluée au moment de la compilation (au moins si constexprles paramètres d'entrée sont fournis ), mais si elle ne peut pas être évaluée au moment de la compilation, elle revient par défaut à un évaluation à l'exécution, comme toute autre fonction normale.

L'aspect au moment de la compilation d'une constexprfonction C ++ en fait une sorte de macro-C, dans la mesure où si une évaluation au moment de la compilation est possible pour une constexprfonction, elle se fera au moment de la compilation, comme une substitution de macro MIN()ou MAX()être entièrement évalué au moment de la compilation en C ou C ++ aussi. Pour des références supplémentaires pour ces informations de modèle C ++, voir ci-dessous.

Références:

  1. https://gcc.gnu.org/onlinedocs/gcc/Typeof.html#Typeof
  2. https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
  3. MIN et MAX en C
  4. Ajout de références de modèle C ++ supplémentaires en avril 2020:
    1. ***** Wikipedia: Template (C ++) <- GRANDES informations supplémentaires sur les modèles C ++!
    2. (Ma propre question et réponse): Pourquoi `constexpr` fait-il partie du prototype de modèle C ++ 14 pour` std :: max () `?
    3. Différence entre `constexpr` et` const`

Clang note de Wikipedia :

[Clang] est conçu pour agir en remplacement de la collection de compilateurs GNU (GCC), prenant en charge la plupart de ses indicateurs de compilation et extensions de langage non officielles.

Gabriel Staples
la source
Au votant des dernières 24 heures: bonne nouvelle! J'ai supprimé ma diatribe de la section 4 que j'ai ajoutée à la section 3 hier, et je l'ai mise ici à la place . Vous êtes invités à réévaluer ma réponse et à lui donner une note positive si vous le souhaitez, car j'y ai mis beaucoup de bonnes informations et j'ai fait de mon mieux pour en faire une réponse canonique solide, utile et bénéfique pour tous. C'est maintenant de nouveau concentré. :) Merci!
Gabriel Staples
4

Il convient de souligner que je pense que si vous définissez minet maxavec le tertiaire tel que

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

puis pour obtenir le même résultat pour le cas spécial de fmin(-0.0,0.0)et fmax(-0.0,0.0)vous devez échanger les arguments

fmax(a,b) = MAX(a,b)
fmin(a,b) = MIN(b,a)
Z boson
la source
Ne fonctionnera toujours pas pour NaN. fmin(3.0,NaN)==fmin(NaN,3.0)==fmax(3.0,NaN)==fmax(NaN,3.0)==3.0
greggo
@greggo, j'ai donné une meilleure réponse ici stackoverflow.com/a/30915238/2542702
Z boson
4

On dirait que Windef.h(a la #include <windows.h>) a maxet min(en minuscules) les macros, qui souffrent également de la difficulté de "double évaluation", mais elles sont là pour ceux qui ne veulent pas relancer les leurs :)

rogerdpack
la source
12
Êtes-vous même surpris?
Matt Joiner
2

Je sais que le gars a dit "C" ... Mais si vous en avez l'occasion, utilisez un modèle C ++:

template<class T> T min(T a, T b) { return a < b ? a : b; }

Tapez safe et aucun problème avec le ++ mentionné dans d'autres commentaires.

Bas Kuenen
la source
16
Les arguments doivent être des références const, vous ne savez jamais quel utilisateur va passer.
nmikhailov
6
Une telle fonction a déjà été standardisée ( std :: min ).
dreamlax
C ++ a beaucoup de fonctions standard pour la plupart des usages normaux, ne réinventez pas la roue. Cependant, MS définit également leur propre min / max, ce qui cause parfois des problèmes
phuclv
0

Le maximum de deux entiers aet best (int)(0.5((a+b)+abs(a-b))). Cela peut également fonctionner avec (double)et fabs(a-b)pour les doubles (similaire pour les flotteurs)

NRZ
la source
Désolé si c'est faux, je suis un débutant en C mais ce code fonctionne pour moi
NRZ
2
Je ne suis pas sûr que cela fonctionne avec des non entiers. Les mathématiques en virgule flottante ont une précision non linéaire.
Treesrule14
Pour développer le commentaire de @ Treesrule14: Cela ne fonctionne pas car les ordinateurs ne traitent pas les nombres de la même manière que les mathématiciens. Le point flottant a des problèmes d'arrondi, il est donc peu probable que vous obteniez la bonne réponse. Même si vous utilisez des mathématiques entières, MAX_INT + MAX_INT donne -2, donc max (MAX_INT, MAX_INT) en utilisant votre formule sortirait comme -1.
user9876
-3

Le moyen le plus simple est de le définir comme une fonction globale dans un .hfichier, et de l'appeler quand vous le souhaitez, si votre programme est modulaire avec beaucoup de fichiers. Sinon, double MIN(a,b){return (a<b?a:b)}c'est le moyen le plus simple.

srezat
la source
1
@technosaurus Il serait utile que vous décriviez pourquoi cette solution est fausse, pas seulement qu'elle l'est.
Tur1ng
@technosaurus, votre réponse est vraiment inutile. Tur1ing, il semble que la fonction est définie complètement incorrecte (types manquants sur les paramètres d'entrée, point-virgule manquant après l'instruction return), et la conversion des entrées int en double est une mauvaise façon de faire les choses, donc le type ne doit pas être double. Une expression define ou statement serait mieux ici (ex: voir ici ), mais si une fonction, envisagez de faire une fonction pour le faire pour les types int32_t, une pour les types uint32_t, et une pour les types float ou double, pour un total de 3 différentes fonctions.
Gabriel Staples
1
@GabrielStaples Cette réponse doit être signalée comme n'étant pas une réponse - cela ne sert à rien. Bien qu'il puisse être utilisé comme un exemple de la façon de se tromper le plus dans le plus petit espace. Recommander des fonctions globales dans un en-tête (même pas en ligne statique?) Cassera le code avec plus de 2 unités de compilation, ne compile même pas, nommant une fonction comme une macro, des entrées implicites comme sa 1989, renvoyant un double sans raison indiquée, implicite lancements qui provoqueront des avertissements au mieux ... et surtout, IL NE RÉPOND PAS À LA QUESTION - pas générique, pas sûr pour le type et certainement pas la meilleure façon
technosaurus
Chacun de ces problèmes mérite une critique supplémentaire qui ne peut être traitée de manière suffisamment détaillée.
technosaurus