MIN e MAX in C


301

Dove sono MINe MAXdefiniti in C, se non del tutto?

Qual è il modo migliore per implementarli, nel modo più generico e digitando nel modo più sicuro possibile? (Preferibilmente estensioni / builtin del compilatore per i compilatori mainstream.)

Risposte:


392

Dove sono MINe MAXdefiniti in C, se non del tutto?

Non lo sono.

Qual è il modo migliore per implementarli, nel modo più generico e sicuro possibile (preferibilmente estensioni / compilatori per compilatori tradizionali).

Come funzioni. Non userei macro come #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)), specialmente se prevedi di distribuire il tuo codice. O scrivi tu stesso, usa qualcosa di simile fmaxo fmin, o correggi la macro usando il tipo di GCC (ottieni anche il bonus di sicurezza della tipografia) in un'espressione dell'istruzione GCC :

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

Tutti dicono "oh, conosco la doppia valutazione, non è un problema" e pochi mesi dopo, eseguirai il debug dei problemi più sciocchi per ore e ore.

Nota l'uso __typeof__invece di typeof:

Se stai scrivendo un file di intestazione che deve funzionare quando incluso nei programmi ISO C, scrivi __typeof__invece di typeof.


68
Sai, sarebbe abbastanza utile se gcc avesse un avvertimento simile a: warning: expression with side-effects multiply evaluated by macronel punto di utilizzo ...
caf

23
@caf: ciò non richiederebbe che il preprocessore abbia una conoscenza più complicata della sintassi C?
dreamlax,

3
Dopo aver tentato molto di capire, non penso che ci sia comunque modo di farlo in VC ++, ma il tuo meglio è cercare di fare confusione con la nuova decltypeparola chiave MSVC ++ 2010 - ma anche così, Visual Studio non può fare istruzioni composte nelle macro (ed decltypeè C ++), ovvero la ({ ... })sintassi di GCC, quindi sono abbastanza sicuro che non sia possibile, comunque. Non ho esaminato nessun altro compilatore in merito a questo problema, mi dispiace Luther: S
David Titarenco,

7
@dreamlax Una volta ho visto un caso in cui qualcuno aveva fatto MAX(someUpperBound, someRandomFunction())per limitare un valore casuale a un limite superiore. Era un'idea terribile, ma non funzionava nemmeno, perché il MAXsuo utilizzo aveva il doppio problema di valutazione, quindi ha finito con un numero casuale diverso da quello inizialmente valutato.
Zev Eisenberg,

8
@Soumen Ad esempio, se si chiama MIN(x++, y++)il preprocessore genererà il seguente codice (((x++) < (y++)) ? (x++) : (y++)). Quindi, xe yverrà incrementato due volte.
Antonio,

91

È anche fornito nelle versioni GNU libc (Linux) e FreeBSD di sys / param.h e ha la definizione fornita da dreamlax.


Su 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.

Su 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))

I repository di origine sono qui:


Ho aggiunto le definizioni dai sistemi a cui ho accesso nella mia risposta sopra (il campo dei commenti non accetta la formattazione per quanto posso dire). Proverà a trovare i collegamenti ai repository di sorgenti di FreeBSD / Linux / glibc.
Mikel,

+1. Molto bella. Funziona anche per openSUSE/Linux 3.1.0-1.2-desktop/ gcc version 4.6.2 (SUSE Linux) . :) Bad non è portatile.
Jack,

Funziona anche su Cygwin.
CMCDragonkai,

1
Aspetta un attimo. Non impedisce la doppia valutazione, vero? : 3
user1857492

76

C'è un std::mine std::maxin C ++, ma AFAIK, non c'è equivalente nella libreria C standard. Puoi definirli tu stesso con macro come

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

Ma questo causa problemi se scrivi qualcosa del genere MAX(++a, ++b).


10
perché mettere troppe parentesi ??? Ho trovato un quiz in cui hanno detto che #define MIN(A, B) ((A < B) ? A : B)non è un modo flessibile, perché ???

79
@Makouda: le parentesi extra nelle macro aiutano a evitare problemi di precedenza dell'operatore. Ad esempio, considera #define MULT(x, y) x * y. Quindi si MULT(a + b, a + b)espande a a + b * a + b, che viene analizzato come a + (b * a) + bdovuto alla precedenza. Non è quello che probabilmente intendeva il programmatore.
dan04,

che non è necessario quando?: ha comunque la precedenza più bassa
Winger Sendon il

1
@WingerSendon: No; l'operatore virgola lo fa.
dan04

24

Evita le estensioni del compilatore non standard e implementale come una macro completamente sicura in standard C puro (ISO 9899: 2011).

Soluzione

#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))

uso

MAX(int, 2, 3)

Spiegazione

La macro MAX crea un'altra macro in base al typeparametro. Questa macro di controllo, se implementata per il tipo specificato, viene utilizzata per verificare che entrambi i parametri siano del tipo corretto. Se latype non è supportato, si verificherà un errore del compilatore.

Se x o y non sono del tipo corretto, si verificherà un errore del compilatore in ENSURE_ macro. È possibile aggiungere più macro di questo tipo se sono supportati più tipi. Ho ipotizzato che verranno utilizzati solo tipi aritmetici (numeri interi, float, puntatori ecc.) E non strutture o matrici ecc.

Se tutti i tipi sono corretti, verrà chiamata la macro GENERIC_MAX. Sono necessarie parentesi extra attorno a ciascun parametro macro, come la consueta precauzione standard quando si scrivono macro C.

Poi ci sono i soliti problemi con le promozioni di tipo implicito in C. L' ?:operatore bilancia il 2 ° e il 3 ° operando l'uno contro l'altro. Ad esempio, il risultato di GENERIC_MAX(my_char1, my_char2)sarebbe un int. Per impedire alla macro di fare promozioni di tipo potenzialmente pericoloso, è stato utilizzato un cast di tipo finale per il tipo previsto.

Fondamento logico

Vogliamo che entrambi i parametri della macro siano dello stesso tipo. Se uno di questi è di tipo diverso, la macro non è più sicura, perché piace a un operatore?: produrrà promozioni di tipo implicito. E poiché lo fa, dobbiamo anche sempre riportare il risultato finale al tipo previsto, come spiegato sopra.

Una macro con un solo parametro avrebbe potuto essere scritta in un modo molto più semplice. Ma con 2 o più parametri, è necessario includere un parametro di tipo aggiuntivo. Perché qualcosa del genere è purtroppo impossibile:

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

Il problema è che se la macro sopra viene chiamata come MAX(1, 2)con due int, tenterà comunque di espandere macro tutti gli scenari possibili _Genericdell'elenco delle associazioni. Quindi anche la ENSURE_floatmacro verrà espansa, anche se non è rilevante int. E poiché quella macro contiene solo intenzionalmente il floattipo, il codice non verrà compilato.

Per risolvere questo problema, ho creato il nome della macro durante la fase di pre-processore, con l'operatore ##, in modo che nessuna macro venga espansa accidentalmente.

Esempi

#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;
}

A GENERIC_MAXproposito, quella macro è una cattiva idea, devi solo cercare GENERIC_MAX(var++, 7)di scoprire perché :-) Al giorno d'oggi (specialmente con compilatori fortemente ottimizzati / integrati), le macro dovrebbero praticamente essere relegate solo ai semplici moduli. Quelle simili a funzioni sono migliori come funzioni e quelle di gruppi di valori migliori come enumerazioni.
paxdiablo,

21

Non penso che siano macro standardizzate. Esistono già funzioni standardizzate per il virgola mobile fmaxe fmin(e fmaxfper i galleggianti e fmaxlper i doppi lunghi).

Puoi implementarli come macro purché tu sia a conoscenza dei problemi degli effetti collaterali / doppia valutazione.

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

Nella maggior parte dei casi, puoi lasciarlo al compilatore per determinare cosa stai cercando di fare e ottimizzarlo nel miglior modo possibile. Sebbene ciò causi problemi se usato in questo modo MAX(i++, j++), dubito che ci sia sempre molto bisogno di controllare il massimo dei valori incrementati in una volta sola. Incrementa prima, quindi controlla.


Questa dovrebbe essere la risposta preferita in quanto ci sono chiaramente funzioni min e max nella libreria matematica: cplusplus.com/reference/cmath/fmax
imranal

@imranal Di cosa stai parlando esattamente? Il codice di implementazione di quelle librerie? Ma quel codice non è esposto , cioè non lo collocano nell'interfaccia della libreria, essendo potenzialmente non sicuro.
Antonio,

@Antonio Penso che tu stia usando definizioni errate di "esposto" e "interfaccia". L'interfaccia della libreria ac sono le variabili esterne, i tipi, le macro e le dichiarazioni di funzione in un file di intestazione; fmin / fmax sono dichiarati nel file header, quindi si dice che siano esposti. Non sono sicuro di ciò a cui ti riferisci come non sicuro.
rationalcoder il

21

Questa è una risposta tardiva, a causa di uno sviluppo abbastanza recente. Poiché l'OP ha accettato la risposta che si basa su un'estensione GCC (e clang) non portatile typeof- o __typeof__per ISO C "pulito" - è disponibile una soluzione migliore a partire da gcc-4.9 .

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

L'ovvio vantaggio di questa estensione è che ogni argomento macro viene espanso solo una volta, a differenza della __typeof__soluzione.

__auto_typeè una forma limitata di C ++ 11 auto. Non può (o non dovrebbe essere?) Essere usato nel codice C ++, sebbene non ci siano buoni motivi per non usare le capacità di inferenza di tipo superiore autoquando si usa C ++ 11.

Detto questo, suppongo che non ci siano problemi nell'uso di questa sintassi quando la macro è inclusa in un extern "C" { ... }ambito; ad esempio, da un'intestazione C. AFAIK, questa estensione non ha trovato il modo in cui il clang delle informazioni


In relazione al commento di Brett Hale , ha clanginiziato a supportare __auto_typeintorno al 2016 (vedi patch ).
Lars

Complimenti per aver riconosciuto il problema con le macro, ma direi comunque che una funzione sarebbe probabilmente migliore :-)
paxdiablo,

@paxdiablo - Sono d'accordo, anche se la domanda ha il c-preprocessortag. Non è garantito che una funzione sia integrata anche con detta parola chiave, a meno che non si usi qualcosa come l' __always_inline__attributo gcc .
Brett Hale,

11

Ho scritto questa versione che funziona per MSVC, GCC, C e 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

1
Ho effettuato l'upgrade ma sono riservati gli identificatori che iniziano con un carattere di sottolineatura seguito da una lettera maiuscola.
dreamlax,

8

Se hai bisogno di min / max per evitare un ramo costoso, non dovresti usare l'operatore ternario, poiché si compila in un salto. Il collegamento seguente descrive un metodo utile per implementare una funzione min / max senza diramazione.

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


1
Se il compilatore è abbastanza intelligente, può evitare il ramo
Axel Gneiting

2
Se l'ottimizzazione è attiva, nella maggior parte dei casi tutti i compilatori moderni emettono una mossa condizionale invece di un ramo, quindi non ha molto senso usare gli hack in questo modo.
Krzysztof Kosiński

2
Assolutamente vero, non ho idea di cosa stavo guardando allora, è passato un po 'di tempo. Sia gcc che clang evitano i rami con -O, sia su x86 che su armv7a.
cib

6

@David Titarenco l'ha inchiodato qui , ma almeno lasciami ripulirlo un po 'per farlo sembrare bello, e mostrare entrambi min() e max() insieme per rendere più facile la copia e l'incollaggio da qui. :)

Aggiornamento 25 aprile 2020: ho anche aggiunto una Sezione 3 per mostrare come ciò sarebbe possibile anche con i modelli C ++, come un prezioso confronto per coloro che imparano sia il C che il C ++ o che passano dall'uno all'altro. Ho fatto del mio meglio per essere accurato, fattuale e corretto per rendere questa risposta un riferimento canonico a cui posso tornare ancora e ancora, e spero che la troviate utile come me.

1. Il vecchio modo macro C:

Questa tecnica è comunemente usata, ben rispettata da coloro che sanno come usarla correttamente, il modo "de facto" di fare le cose, e va bene se usata correttamente, ma buggy (pensate: effetto collaterale a doppia valutazione ) se mai passare espressioni tra cui assegnazione variabile per confrontare:

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

2. Il nuovo e migliorato modo " espressione espressione " di gcc :

Questa tecnica evita gli effetti collaterali e gli errori "doppia valutazione" sopra indicati ed è quindi considerata il modo GCC C superiore, più sicuro e "più moderno" per farlo. Aspettatevi che funzioni con entrambi i compilatori gcc e clang, dal momento che clang è, per progettazione, compatibile con gcc (vedere la nota clang in fondo a questa risposta).

MA: fai attenzione agli effetti di " ombreggiatura variabile ", poiché le espressioni delle istruzioni sono apparentemente in linea e quindi NON hanno il loro ambito variabile 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;       \
})

Si noti che nelle espressioni dell'istruzione gcc, l' ultima espressione nel blocco di codice è ciò che viene "restituito" dall'espressione, come se fosse restituito da una funzione. La documentazione di GCC lo dice in questo modo:

L'ultima cosa nell'istruzione composta dovrebbe essere un'espressione seguita da un punto e virgola; il valore di questa sottoespressione funge da valore dell'intero costrutto. (Se si utilizza un altro tipo di istruzione ultimo tra parentesi graffe, il costrutto ha il tipo vuoto, e quindi effettivamente nessun valore.)

3. Il modello C ++:

Nota C ++: se si utilizza C ++, i modelli sono probabilmente consigliati per questo tipo di costrutto, ma personalmente non mi piacciono i modelli e probabilmente utilizzerei comunque uno dei costrutti sopra in C ++, dato che spesso uso e preferisco gli stili C anche nel C ++ incorporato.

Questa sezione ha aggiunto il 25 aprile 2020:

Ho fatto un sacco di C ++ negli ultimi mesi e la pressione di preferire i template alle macro, ove possibile, nella comunità C ++ è piuttosto forte. Di conseguenza, sto migliorando nell'uso dei modelli e desidero inserire qui le versioni dei modelli C ++ per completezza e rendere questa una risposta più canonica e completa.

Ecco quali versioni di base del modello di funzionemax() e min()potrebbero apparire in 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;
}

Fai ulteriori letture sui modelli C ++ qui: Wikipedia: Template (C ++) .

Tuttavia, entrambi max()e min()fanno già parte della libreria standard C ++, <algorithm>nell'intestazione ( #include <algorithm>). Nella libreria standard C ++ sono definiti in modo leggermente diverso rispetto a quelli che ho sopra. I prototipi predefiniti per std::max<>()e std::min<>(), ad esempio, in C ++ 14, osservando i loro prototipi nei collegamenti cplusplus.com appena sopra, sono:

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);

Tieni presente che la parola chiave typenameè un alias class(quindi il loro utilizzo è identico sia che tu lo dica <typename T>o <class T>), poiché è stato successivamente riconosciuto dopo l'invenzione dei modelli C ++, che il tipo di modello potrebbe essere un tipo regolare ( int,float , etc.) anziché soltanto un tipo di classe.

Qui puoi vedere che sono entrambi i tipi di input, così come il tipo restituito const T&, che significa "riferimento costante al tipo T". Ciò significa che i parametri di input e il valore restituito vengono passati per riferimento anziché passati per valore . È come passare da puntatori ed è più efficiente per tipi di grandi dimensioni, come gli oggetti di classe. La constexprparte della funzione modifica la funzione stessa e indica che la funzione deve essere in grado di essere valutata in fase di compilazione (almeno se vengono forniti i constexprparametri di input), ma se non può essere valutata in fase di compilazione, per impostazione predefinita torna a valutazione di runtime, come qualsiasi altra normale funzione.

L'aspetto in fase di compilazione di una constexprfunzione C ++ lo rende un po 'simile a C-macro, in quanto se una valutazione in fase di compilazione è possibile per una constexprfunzione, verrà eseguita in fase di compilazione, come potrebbe essere una sostituzione MIN()o MAX()macro essere valutato completamente in fase di compilazione anche in C o C ++. Per ulteriori riferimenti per queste informazioni sul modello C ++, vedere di seguito.

Riferimenti:

  1. https://gcc.gnu.org/onlinedocs/gcc/Typeof.html#Typeof
  2. https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
  3. MIN e MAX in C
  4. Ulteriori riferimenti al modello C ++ aggiunti ad aprile 2020:
    1. ***** Wikipedia: Template (C ++) <- GRANDI informazioni aggiuntive sui template C ++!
    2. (La mia domanda e risposta): Perché `constexpr` fa parte del prototipo del modello C ++ 14 per` std :: max () `?
    3. Differenza tra `constexpr` e` const`

Nota Clang da Wikipedia :

[Clang] è progettato per fungere da sostituto drop-in per la GNU Compiler Collection (GCC), supportando la maggior parte dei suoi flag di compilazione e estensioni di linguaggio non ufficiali.


Al downvoter delle ultime 24 ore: buone notizie! Ho rimosso il mio rant di Sezione 4 che ho aggiunto ieri con la Sezione 3 e l'ho inserito qui . Ti invitiamo a rivalutare la mia risposta e dare un voto se vuoi, poiché ho inserito molte buone informazioni e ho fatto del mio meglio per renderla una risposta solida, utile e canonica a beneficio di tutti. Ora è tornato a essere concentrato. :) Grazie!
Gabriel Staples,

4

Vale la pena sottolineare che penso che se si definisce mine maxcon il terziario come

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

quindi per ottenere lo stesso risultato per il caso speciale di fmin(-0.0,0.0)ed fmax(-0.0,0.0)è necessario scambiare gli argomenti

fmax(a,b) = MAX(a,b)
fmin(a,b) = MIN(b,a)

Non funzionerà ancora per NaN. fmin(3.0,NaN)==fmin(NaN,3.0)==fmax(3.0,NaN)==fmax(NaN,3.0)==3.0
Greggo,

@greggo, ho dato una risposta migliore qui stackoverflow.com/a/30915238/2542702
Z boson

4

Sembra che Windef.h(a la #include <windows.h>) abbia maxe min(minuscole) macro, che soffrono anche della difficoltà della "doppia valutazione", ma sono lì per coloro che non vogliono ripetere il rollback :)


12
Sei anche sorpreso?
Matt Joiner,

2

So che il ragazzo ha detto "C" ... Ma se ne hai la possibilità, usa un modello C ++:

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

Digitare sicuro e nessun problema con il ++ menzionato in altri commenti.


16
Gli argomenti dovrebbero essere riferimenti costanti, non si sa mai quale utente passerà.
nmikhailov,

6
Tale funzione è già stata standardizzata ( std :: min ).
dreamlax,

Il C ++ ha molte funzioni standard per la maggior parte degli scopi normali, non reinventare la ruota. Tuttavia, la SM definisce anche il proprio min / max che a volte causa problemi
phuclv,

0

Il massimo di due numeri interi aed bè (int)(0.5((a+b)+abs(a-b))). Questo può funzionare anche con (double)e fabs(a-b)per i doppi (simile per i float)


Scusami se è sbagliato, sono un principiante in C ma questo codice funziona per me
NRZ

2
Non sono sicuro che funzioni con numeri non interi. La matematica in virgola mobile ha una precisione non lineare.
Treesrule14

Per espandere il commento di @ Treesrule14: questo non funziona perché i computer non trattano i numeri allo stesso modo dei matematici. Il virgola mobile presenta problemi di arrotondamento, quindi è improbabile che tu ottenga la risposta giusta. Anche se usi i numeri interi, MAX_INT + MAX_INT fornisce -2, quindi max (MAX_INT, MAX_INT) usando la tua formula verrebbe fuori come -1.
user9876

-3

Il modo più semplice è definirlo come una funzione globale in un .hfile e chiamarlo quando vuoi, se il tuo programma è modulare con molti file. In caso contrario, double MIN(a,b){return (a<b?a:b)}è il modo più semplice.


1
@technosaurus Sarebbe utile se descrivessi perché questa soluzione è sbagliata, non solo.
Tur1ng

@technosaurus, la tua risposta è davvero inutile. Tuttavia, sembra che la funzione sia definita completamente errata (tipi mancanti sui parametri di input, punto e virgola mancante dopo l'istruzione return) e convertire gli input int in double è un modo scadente di fare le cose, quindi il tipo non dovrebbe essere doppio. Un'espressione di definizione o istruzione sarebbe meglio qui (es: vedi qui ), ma se una funzione, considera l'idea di creare una funzione per farlo per i tipi int32_t, una per i tipi uint32_t e una per i tipi float o double, per un totale di 3 funzioni diverse.
Gabriel Staples,

1
@GabrielStaples Questa risposta dovrebbe essere contrassegnata come non una risposta - non c'è aiuto. Anche se potrebbe essere usato come esempio di come essere il più sbagliato nel minimo spazio. Raccomandare funzioni globali in un'intestazione (neanche statico in linea?) Spezzerà il codice con 2+ unità di compilazione, non si compila nemmeno, nominando una funzione come una macro, implica impliciti come il suo 1989, restituendo un doppio senza motivo dichiarato, implicito cast che causeranno avvisi nella migliore delle ipotesi ... e, soprattutto, NON RISPONDE ALLA DOMANDA - non generico, non sicuro per i tipi e sicuramente non il migliore
technosaurus

Ognuno di questi problemi merita ulteriori critiche che non possono essere trattate in modo sufficientemente dettagliato.
technosaurus,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.