C cinsinden MIN ve MAX


301

Nerede MINve nerede MAXC tanımlanmış?

Bunları genel olarak uygulamak ve mümkün olduğunca güvenli bir şekilde yazmak için en iyi yol nedir? (Ana derleyiciler için derleyici uzantıları / yerleşimleri tercih edilir.)

Yanıtlar:


392

Nerede MINve nerede MAXC tanımlanmış?

Onlar değil.

Bunları uygulamanın en iyi yolu, mümkün olduğunca genel ve güvenli yazın (ana derleyiciler için derleyici uzantıları / yerleşikler tercih edilir).

Fonksiyonlar olarak. #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))Özellikle kodunuzu dağıtmayı planlıyorsanız, gibi makroları kullanmam . Kendi yazınızı yazın, standart gibi bir şey kullanın fmaxya fminda bir GCC deyimi ifadesinde makroyu GCC'nin typeof (daktilo güvenlik bonusu alırsınız) kullanarak düzeltin :

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

Herkes "ah, çift değerlendirmeyi biliyorum, sorun değil" der ve birkaç ay yolda, en sessiz problemleri saatlerce ayıklayacaksınız.

__typeof__Bunun yerine kullanımına dikkat edin typeof:

ISO C programlarına dahil edildiğinde çalışması gereken bir başlık dosyası yazıyorsanız, __typeof__bunun yerine yazın typeof.


68
Biliyorsunuz, gcc'nin şu hatlarda bir uyarı alması oldukça kullanışlı olurdu: warning: expression with side-effects multiply evaluated by macrokullanım noktasında ...
caf

23
@caf: önişlemcinin daha karmaşık bir C sözdizimi bilgisine sahip olmasını gerektirmez mi?
dreamlax

3
Çok anlamaya çalıştıktan sonra, VC ++ bunu yapmak için yine de sanmıyorum, ama en iyisi MSVC ++ 2010 yeni decltypeanahtar kelime ile uğraşmak için denemek - ama öyle olsa bile, Visual Studio makrolarda bileşik ifadeler yapamaz (ve decltypeyine de C ++), yani GCC ({ ... })sözdizimi, bu yüzden zaten mümkün olmadığından eminim. Bu konuyla ilgili başka bir derleyiciye bakmadım, üzgünüm Luther: S
David Titarenco

7
@dreamlax Bir keresinde birinin MAX(someUpperBound, someRandomFunction())rastgele bir değeri bir üst sınırla sınırlandırdığı bir durum gördüm . Bu korkunç bir fikirdi, ama işe yaramadı, çünkü MAXkullandığı çift değerlendirme sorunu vardı, bu yüzden başlangıçta değerlendirilenden farklı bir rastgele sayı ile sonuçlandı.
Zev Eisenberg

8
@Soumen Örneğin MIN(x++, y++), önişlemciyi çağırırsanız aşağıdaki kodu oluşturur (((x++) < (y++)) ? (x++) : (y++)). Yani, xve yiki kez artırılacak.
Antonio

91

Ayrıca sys / param.h'nin GNU libc (Linux) ve FreeBSD sürümlerinde sağlanır ve dreamlax tarafından sağlanan tanıma sahiptir.


Debian'da:

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

FreeBSD'de:

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

Kaynak depolar burada:


Yukarıdaki cevabımda erişebildiğim sistemlerin tanımlarını ekledim (yorum alanı, anlayabildiğim kadarıyla biçimlendirmeyi kabul etmiyor). FreeBSD / Linux / glibc kaynak depolarının bağlantılarını bulmaya çalışacaktır.
Mikel

+1. Çok hoş. İçin Works openSUSE/Linux 3.1.0-1.2-desktop/ ' gcc version 4.6.2 (SUSE Linux) de. :) Kötü taşınabilir değil.
Jack

Cygwin üzerinde de çalışır.
CMCDragonkai

1
Biraz bekle. Çifte değerlendirmeyi engellemez, değil mi? : 3
user1857492

76

C ++ 'da bir std::minve vardır std::max, ancak AFAIK, C standart kütüphanesinde eşdeğer değildir. Bunları kendiniz gibi makrolarla tanımlayabilirsiniz

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

Ama böyle bir şey yazarsanız sorunlara neden olur MAX(++a, ++b).


10
neden çok fazla parantez koymak ??? #define MIN(A, B) ((A < B) ? A : B)Esnek bir yol olmadığını söyledikleri bir sınav buldum , neden ???

79
@ Makouda: Makrolardaki fazladan parantezler, operatör öncelik sorunlarının önlenmesine yardımcı olur. Örneğin, düşünün #define MULT(x, y) x * y. Daha sonra önceliğe bağlı olarak ayrışan MULT(a + b, a + b)genişler . Programcı muhtemelen bunu istemiyordu. a + b * a + ba + (b * a) + b
dan04

ne zaman gerekli değil
?:

1
@WingerSendon: Yapmıyor; virgül operatörü yapar.
dan04

24

Standart olmayan derleyici uzantılarından kaçının ve saf standart C'de tamamen güvenli bir makro olarak uygulayın (ISO 9899: 2011).

Çözüm

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

kullanım

MAX(int, 2, 3)

açıklama

MAX makrosu, typeparametreye dayalı olarak başka bir makro oluşturur . Bu kontrol makrosu, verilen tip için uygulanırsa, her iki parametrenin de doğru tipte olup olmadığını kontrol etmek için kullanılır. Eğer typedesteklenmiyorsa, bir derleyici hatası olacaktır.

X veya y doğru türde değilse, ENSURE_makrolarda bir derleyici hatası olacaktır . Daha fazla tür destekleniyorsa, bu tür daha fazla makro eklenebilir. Yapılar veya diziler değil, sadece aritmetik türlerin (tamsayılar, kayan noktalar, işaretçiler vb.) Kullanılacağını varsaydım.

Tüm türler doğruysa, GENERIC_MAX makrosu çağrılır. C makroları yazarken her zamanki standart önlem olarak, her makro parametresi etrafında ekstra parantez gereklidir.

Sonra C'de örtük tür tanıtımları ile ilgili olağan problemler vardır. ?:Operatör 2. ve 3. işlenenleri birbiriyle dengeler. Örneğin, sonucu GENERIC_MAX(my_char1, my_char2)bir olur int. Makronun bu tür potansiyel olarak tehlikeli tür tanıtımlarını yapmasını önlemek için, amaçlanan türe dökülen bir son tür kullanılmıştır.

gerekçe

Makroya ilişkin her iki parametrenin de aynı türde olmasını istiyoruz. Bunlardan biri farklı bir türdeyse, makro artık tür güvenli değildir, çünkü böyle bir operatör ?:örtük tür tanıtımları verir. Ve öyle olduğu için, nihai sonucu her zaman yukarıda açıklanan amaçlanan türe geri döndürmemiz gerekir.

Sadece bir parametreli bir makro çok daha basit bir şekilde yazılabilirdi. Ancak 2 veya daha fazla parametre ile, ekstra tip parametresi eklemeye ihtiyaç vardır. Çünkü böyle bir şey maalesef imkansız:

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

Sorun yukarıdaki makro MAX(1, 2)iki ile çağrılırsa int, yine de _Genericilişkilendirme listesinin tüm olası senaryolarını makro genişletmeye çalışacaktır . Dolayısıyla, ENSURE_floatilgili olmasa bile makro da genişletilecektir int. Bu makro kasıtlı olarak yalnızca floattürü içerdiğinden kod derlenmez.

Bunu çözmek için, makro adını ## operatörü ile ön işlemci aşaması sırasında oluşturdum, böylece hiçbir makro yanlışlıkla genişletilmez.

Örnekler

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

Bu GENERIC_MAXmakro bu arada kötü bir fikir, sadece GENERIC_MAX(var++, 7)nedenini bulmaya çalışmalısın :-) Günümüzde (özellikle yoğun optimizasyon / satır içi derleyicileri ile), makrolar sadece basit formlara indirgenmelidir. Fonksiyona benzer olanlar fonksiyonlar kadar, değer grubu ise numaralandırma olarak daha iyidir.
paxdiablo

21

Standart makrolar olduklarını düşünmüyorum. Zaten kayan nokta için fmaxve fmin( fmaxfşamandıralar ve fmaxluzun çiftler için) standart fonksiyonlar vardır .

Yan etkiler / çift değerlendirme konularından haberdar olduğunuz sürece bunları makro olarak uygulayabilirsiniz.

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

Çoğu durumda, ne yapmaya çalıştığınızı belirlemek ve mümkün olan en iyi şekilde optimize etmek için derleyiciye bırakabilirsiniz. Bu gibi kullanıldığında sorunlara neden olsa da MAX(i++, j++), bir seferde maksimum artan değerlerin kontrol edilmesine ihtiyaç duyulduğundan şüpheliyim. Önce artırın, sonra kontrol edin.


Matematik kütüphanesinde min ve max işlevleri açıkça olduğu için bu tercih edilen cevap olmalıdır: cplusplus.com/reference/cmath/fmax
imranal

@imranal Tam olarak neden bahsediyorsun? Bu kütüphanenin uygulama kodu? Ancak bu kod açığa çıkmaz , yani potansiyel olarak güvensiz olarak kütüphanenin arayüzüne yerleştirmezler.
Antonio

@Antonio Ben "maruz" ve "arayüz" yanlış tanımları kullandığınızı düşünüyorum. Ac kütüphanesinin arabirimi, bir başlık dosyasındaki eklenmiş değişkenler, türler, makrolar ve işlev bildirimleridir; fmin / fmax başlık dosyasında bildirilir, bu nedenle bunların açığa çıktığı söylenir. Ne güvensiz olarak bahsettiğinizden emin değilim.
rationalcoder

21

Bu oldukça yakın bir gelişme nedeniyle geç bir cevaptır. OP, taşınabilir olmayan bir GCC (ve clang) uzantısına typeofveya __typeof__'temiz' ISO C'ye dayanan cevabı kabul ettiğinden , gcc-4.9'dan daha iyi bir çözüm var .

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

Bu uzantının bariz yararı, __typeof__çözümün aksine her makro argümanının yalnızca bir kez genişletilmesidir .

__auto_typeC ++ 11'lerin sınırlı bir formudur auto. autoC ++ 11 kullanıldığında üstün tip çıkarsama özelliklerini kullanmamak için iyi bir neden olmasa da, C ++ kodunda kullanılamaz (veya kullanılmamalıdır?) .

Bununla birlikte, makro bir kapsama dahil edildiğinde bu sözdizimini kullanan herhangi bir sorun olmadığını varsayıyorumextern "C" { ... } ; örneğin, bir C başlığından. AFAIK, bu uzantı kendi yolunu bulmadı clang


İlgili Brett Hale açıklama , clangdesteklemeye başladı __auto_type(bkz etrafında 2016 yama ).
Lars

Makro problemi tanıdığı için Kudos ama yine de bir fonksiyonun muhtemelen daha iyi olacağını söyleyebilirim :-)
paxdiablo

@paxdiablo - Katılıyorum, ancak sorunun c-preprocessoretiketi var. Gcc'nin __always_inline__niteliği gibi bir şey kullanılmadığı sürece, bir işlevin adı geçen anahtar kelimeyle bile satır içinde olması garanti edilmez .
Brett Hale

11

MSVC, GCC, C ve C ++ için çalışan bu sürümü yazdım .

#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
İptal ettim ancak büyük harfle alt çizgi ile başlayan tanımlayıcılar saklıdır.
dreamlax

8

Pahalı bir daldan kaçınmak için min / max'a ihtiyacınız varsa, üçlü operatörü kullanmamalısınız, çünkü bir sıçramaya kadar derlenir. Aşağıdaki bağlantı dallanma olmadan bir min / maks fonksiyonunun uygulanması için kullanışlı bir yöntemi tarif etmektedir.

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


1
Derleyici yeterince
akıllıysa

2
Optimizasyon açıksa, tüm modern derleyiciler dal yerine koşullu bir hareket yayar, bu nedenle bu tür hack'leri kullanmanın çok az anlamı vardır.
Krzysztof Kosiński

2
Kesinlikle doğru, o zamanlar ne aradığımı bilmiyorum, uzun zaman oldu. Hem gcc hem de clang, x86 ve armv7a'da -O ile dallardan kaçınır.
cib

6

@ David Titarenco buradan çivilenmiş , ama güzel görünmesi ve her iki göstermeye temiz, en azından onu biraz beni let min() ve max() kopyalayarak ve burada daha kolay elde yapıştırarak yapmak için bir araya. :)

Güncelleme 25 Nisan 2020: Ayrıca, C ve C ++ öğrenenler veya birinden diğerine geçiş yapanlar için değerli bir karşılaştırma olarak, bunun C ++ şablonlarıyla nasıl yapılacağını göstermek için bir Bölüm 3 ekledim. Bu cevabı tekrar tekrar geri getirebileceğim kanonik bir referans yapmak için kapsamlı ve olgusal ve doğru olmak için elimden geleni yaptım ve umarım bunu benim kadar yararlı bulursunuz.

1. Eski C makro yolu:

Bu teknik yaygın olarak kullanılır, düzgün bir şekilde nasıl kullanılacağını bilenler, bir şeyler yapmanın "de facto" yolu ve uygun şekilde kullanılırsa iyi kullanılır, ancak buggy (düşünün: çift ​​değerlendirme yan etkisi ) karşılaştırmak için değişken atama dahil ifadeleri hiç geçmeyin :

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

2. Yeni ve geliştirilmiş gcc " ifade ifadesi " yolu:

Bu teknik yukarıdaki "çift değerlendirme" yan etkilerini ve hatalarını önler ve bu nedenle bunu yapmanın üstün, daha güvenli ve "daha modern" GCC C yolu olarak kabul edilir. Hem gcc hem de clang derleyicileriyle çalışmasını bekleyin, çünkü clang tasarım gereği gcc uyumludur (bu cevabın altındaki clang notuna bakın).

AMA: " İfade ifadeleri açıkça satır içi olduğundan ve bu nedenle kendi yerel değişken kapsamına sahip OLMADIĞI değişken gölgeleme " etkilerine !

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

Gcc deyimi ifadelerinde, kod bloğundaki son ifadenin , bir işlevden döndürülmüş gibi ifadeden "döndürülen" ifadesi olduğunu unutmayın.GCC'nin belgeleri bunu şöyle söylüyor:

Bileşik deyimindeki son şey bir ifade ve ardından noktalı virgül olmalıdır; bu alt ifadenin değeri tüm yapının değeri olarak işlev görür. (Parantez içinde başka tür bir ifade kullanırsanız, yapının türü geçersizdir ve dolayısıyla etkili bir şekilde değeri yoktur.)

3. C ++ şablon yolu:

C ++ Not: C ++ kullanılıyorsa, şablonlar muhtemelen bu tür yapı için önerilir, ancak şablonları kişisel olarak beğenmedim ve muhtemelen C ++ 'da yukarıdaki yapılardan birini kullanacağım, çünkü sık sık gömülü C ++' da C stillerini kullanıyorum ve tercih ediyorum.

Bu bölüm 25 Nisan 2020'yi ekledi:

Geçtiğimiz birkaç ay boyunca bir ton C ++ yapıyorum ve makroları şablonlar üzerinde tercih etme baskısı, mümkün olduğunda, C ++ topluluğunda oldukça güçlü. Sonuç olarak, şablonları kullanma konusunda daha iyi hale geldim ve C ++ şablon sürümlerini tamlık sağlamak ve bunu daha kanonik ve kapsamlı bir cevap haline getirmek istiyorum.

İşte temel işlev şablonu sürümleri max()ve min()C ++ gibi görünebilir:

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

Burada C ++ şablonları hakkında ek okuma yapın: Wikipedia: Template (C ++) .

Ancak, her iki max()ve min()daha önce de C ++ standart bir kütüphanenin bir parçası olarak <algorithm>başlığının ( #include <algorithm>). C ++ standart kütüphanesinde, yukarıda gördüğümden biraz farklı tanımlanırlar. C ++ 14 için std::max<>()ve std::min<>()örneğin, yukarıdaki cplusplus.com bağlantılarındaki prototiplerine bakarak varsayılan prototipler şunlardır:

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

Anahtar kelimenin o Not typenameiçin bir takma addır class(kullanımları diyorsunuz göre denktir yüzden <typename T>ya <class T>sonradan C ++ şablonları icadından sonra kabul edildi beri şablon türü düzenli bir tip olabileceğini,) ( int, floatvs.) yerine sadece sınıf türü.

Burada hem giriş türlerinin hem de dönüş türünün olduğunu görebilirsiniz const T&, bu da "türe sürekli başvuru" anlamına gelir T. Bu giriş parametreleri ve dönüş değeri anlamına gelir , referans ile geçirilen yerine değeri tarafından iletilir . Bu işaretçilerden geçmek gibidir ve sınıf nesneleri gibi büyük tipler için daha etkilidir. constexprİşlevinin bir parçası işlevlerinin değiştirir ve fonksiyon gösterir yeteneğine sahip olmalıdır eğer varsa, en az derleme zamanında (en değerlendirilenconstexpr derleme zamanında değerlendirilen olamaz sonra varsayılan A geri, girdi parametreleri), ancak diğer normal fonksiyonlarda olduğu gibi çalışma zamanı değerlendirmesi.

Bir constexprC ++ işlevinin derleme zamanı özelliği, bir tür C-makro benzeri olmasını sağlar, çünkü bir constexprişlev için derleme zamanı değerlendirmesi mümkünse , derleme zamanında, bir MIN()veyaMAX() makro değiştirme belki olabilir derleme zamanında C veya C ++ 'da da tam olarak değerlendirilmelidir. Bu C ++ şablon bilgisi için ek başvurular için aşağıya bakın.

Referanslar:

  1. https://gcc.gnu.org/onlinedocs/gcc/Typeof.html#Typeof
  2. https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
  3. C cinsinden MIN ve MAX
  4. Ek C ++ şablon başvuruları Nisan 2020 eklendi:
    1. ***** Wikipedia: Şablon (C ++) <- C ++ şablonları hakkında BÜYÜK ek bilgi!
    2. (Kendi sorum ve cevabım): `constexpr` neden` ​​std :: max () `için C ++ 14 şablon prototipinin bir parçası?
    3. "Constexpr" ve "const" arasındaki fark

Wikipedia'dan Clang notu :

[Clang], derleme bayraklarının ve gayri resmi dil uzantılarının çoğunu destekleyen GNU Derleyici Koleksiyonu'nun (GCC) yerine geçecek şekilde tasarlanmıştır.


Son 24 saatteki düşüşe: iyi haber! Dün Bölüm 3 ile eklediğim Bölüm 4 rantımı kaldırdım ve onun yerine buraya koydum . Cevabımı yeniden değerlendirebilir ve lütfen eğer bir sürü iyi bilgi koyduğum ve herkese fayda sağlamak için sağlam, yararlı, kanonik bir cevap yapmak için elimden gelenin en iyisini yaptığınız takdirde bir oylama yapabilirsiniz. Şimdi odaklanmaya geri döndü. :) Teşekkürler!
Gabriel Staples

4

Bence dışarı Bu değer işaret var tanımladığınız eğer minve maxolarak üçüncül böyle ile

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

Daha sonra özel durum için aynı sonucu elde etmek için fmin(-0.0,0.0)ve fmax(-0.0,0.0)size argümanları takas gerekir

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

Hala NaN için çalışmaz. fmin(3.0,NaN)==fmin(NaN,3.0)==fmax(3.0,NaN)==fmax(NaN,3.0)==3.0
greggo

@greggo, burada daha iyi bir cevap verdim stackoverflow.com/a/30915238/2542702
Z bozonu

4

Görünüşe göre Windef.h(la #include <windows.h>) maxve min"küçük değerlendirme" zorluğundan muzdarip (küçük harf) makroları var, ancak kendi rollerini yeniden almak istemeyenler için oradalar :)


12
Şaşırdın mı?
Matt Joiner

2

Adamýn "C" dediđini biliyorum ... Ama ţansýn varsa, bir C ++ şablonu kullan:

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

Güvenli yazın ve diğer yorumlarda belirtilen ++ ile sorun yok.


16
Bağımsız değişkenler const referansları olmalıdır, kullanıcının ne geçeceğini asla bilemezsiniz.
nmikhailov

6
Böyle bir işlev zaten standartlaştırılmıştır ( std :: min ).
dreamlax

C ++ normal amaçların çoğu için birçok standart fonksiyona sahiptir, tekerleği yeniden icat etmeyin. Bununla birlikte MS, bazen soruna neden olan kendi min /
maks'lerini

0

İki tam sayının maksimum ave bolduğunu (int)(0.5((a+b)+abs(a-b))). Bu, çiftler için (double)ve fabs(a-b)çiftler için de kullanılabilir (şamandıralar için benzer)


Üzgünüm, bu yanlışsa, ben bir C acemiyim ama bu kod benim için çalışıyor
NRZ

2
Tamsayı olmayanlarla çalıştığından emin değilim. Kayan nokta matematiği doğrusal olmayan bir hassasiyete sahiptir.
Treesrule14

@ Treesrule14'ün yorumunu genişletmek için: Bilgisayarlar sayılara matematikçilerle aynı şekilde davranmadığı için bu işe yaramıyor. Kayan noktanın yuvarlama sorunları vardır, bu nedenle doğru cevabı almanız olası değildir. Tamsayı matematik kullansanız bile, MAX_INT + MAX_INT -2 değerini verir, bu nedenle formülünüzü kullanan max (MAX_INT, MAX_INT) -1 olarak ortaya çıkar.
user9876

-3

En basit yol, onu bir .hdosyada global bir işlev olarak tanımlamak ve programınız çok sayıda dosya ile modüler ise, istediğiniz zaman çağırmaktır. Değilse double MIN(a,b){return (a<b?a:b)}, en basit yol.


1
@technosaurus Bu çözümün neden sadece yanlış olduğunu değil, neden yanlış olduğunu açıklamanız yararlı olacaktır.
Tur1ng

@technosaurus, yanıtınız gerçekten yararsızdır. Tur1ing, fonksiyonun tamamen yanlış tanımlandığı anlaşılıyor (giriş parametrelerinde eksik türler, return deyiminden sonra noktalı virgül eksik) ve int girişlerini ikiye dönüştürmek kötü bir yöntemdir, bu nedenle tür çift olmamalıdır. Bir tanım veya deyim ifadesi burada daha iyi olur (ör: buraya bakın ), ancak bir işlev, int32_t türleri için, biri uint32_t türleri için ve biri kayan nokta veya çift türler için toplam 3 olmak üzere bir işlev yapmayı düşünün. farklı işlevler.
Gabriel Staples

1
@GabrielStaples Bu cevap bir cevap değil olarak işaretlenmelidir - yardım yoktur. Her ne kadar en küçük alandaki en yanlış olmanın bir örneği olarak kullanılabilir. Bir başlıktaki global işlevleri tavsiye etmek (hatta statik satır içi değil?) 2+ derleme birimi ile kodu kıracaktır, hatta bir makro gibi bir işlevi adlandırmak, 1989 gibi ima edilen, ima edilen herhangi bir sebep olmadan bir çift döndürmek, en iyi uyarılara neden olacak dökümler ... ve en önemlisi SORU CEVAP DEĞİL - jenerik değil, tip güvenli değil ve kesinlikle en iyi yol değil
technosaurus

Bu sorunların her biri, yeterince ayrıntılı olarak ele alınamayan daha fazla eleştiriyi hak ediyor.
technosaurus
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.