C में MIN और MAX


299

C में कहां MINऔर क्या MAXपरिभाषित किया गया है, यदि बिलकुल नहीं है?

इन्हें लागू करने का सबसे अच्छा तरीका क्या है, जैसा कि सामान्य रूप से संभव है और सुरक्षित रूप से टाइप करें? (कम्पाइलर एक्सटेंशन / मेनस्ट्रीम कम्पाइलर के लिए निर्मित भवन को प्राथमिकता दी।)

जवाबों:


392

C में कहां MINऔर क्या MAXपरिभाषित किया गया है, यदि बिलकुल नहीं है?

वे नहीं कर रहे हैं

इन्हें लागू करने का सबसे अच्छा तरीका क्या है, जैसा कि सामान्य रूप से संभव है और संभव के रूप में सुरक्षित है (मुख्यधारा के संकलक के लिए संकलक एक्सटेंशन / निर्मित)।

कार्यों के रूप में। #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))यदि आप अपने कोड को तैनात करने की योजना बनाते हैं , तो मैं विशेष रूप से मैक्रोज़ का उपयोग नहीं करूंगा । या तो अपने स्वयं के, मानक की तरह कुछ उपयोग लिखने fmaxया fmin, या का उपयोग कर मैक्रो ठीक जीसीसी के typeof एक में (आप typesafety भी बोनस प्राप्त) जीसीसी बयान अभिव्यक्ति :

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

हर कोई कहता है "ओह मैं दोहरे मूल्यांकन के बारे में जानता हूं, यह कोई समस्या नहीं है" और सड़क से कुछ महीने नीचे, आप अंत में घंटों के लिए सबसे कठिन समस्याओं को डिबग करेंगे।

के __typeof__बजाय के उपयोग पर ध्यान दें typeof:

यदि आप एक हेडर फ़ाइल लिख रहे हैं जो आईएसओ सी कार्यक्रमों में शामिल होने पर काम करना चाहिए, तो __typeof__इसके बजाय लिखें typeof


68
तुम्हें पता है, यह काफी आसान होगा अगर gcc की तर्ज पर एक चेतावनी थी: warning: expression with side-effects multiply evaluated by macroउपयोग के बिंदु पर ...
Caf

23
@caf: यह आवश्यक नहीं होगा कि प्रीप्रोसेसर को सी सिंटैक्स का अधिक जटिल ज्ञान हो?
ड्रीमलैक्स

3
बहुत जानने की कोशिश करने के बाद, मुझे नहीं लगता कि वीसी ++ में ऐसा करने के लिए वैसे भी है, लेकिन आपका सबसे अच्छा एमएसवीसी ++ 2010 नए decltypeकीवर्ड के साथ गड़बड़ करने की कोशिश करना है - लेकिन फिर भी, मैक्रो में विज़ुअल स्टूडियो यौगिक कथनों को नहीं कर सकता है (और decltypeवैसे भी C ++ है), यानी GCC का ({ ... })सिंटैक्स तो मुझे पूरा यकीन है कि यह वैसे भी संभव नहीं है। मैं इस मुद्दे के बारे में किसी भी अन्य संकलक पर नहीं देखा है, खेद लूथर: एस
डेविड Titarenco

7
@dreamlax मैंने एक बार एक मामला देखा था जहां किसी ने MAX(someUpperBound, someRandomFunction())कुछ ऊपरी सीमा तक यादृच्छिक मान को सीमित करने के लिए किया था । यह एक भयानक विचार था, लेकिन यह भी काम नहीं करता था, क्योंकि MAXवह दोहरे मूल्यांकन की समस्या का उपयोग कर रहा था, इसलिए वह शुरू में मूल्यांकन किए गए की तुलना में एक अलग यादृच्छिक संख्या के साथ समाप्त हो गया।
ज़ेव ईसेनबर्ग

8
@Soumen उदाहरण के लिए, यदि आप MIN(x++, y++)प्रीप्रोसेसर को कॉल करते हैं , तो निम्न कोड उत्पन्न होगा (((x++) < (y++)) ? (x++) : (y++))। तो, xऔर yदो बार वेतन वृद्धि की जाएगी।
एंटोनियो

91

यह GNU libc (लिनक्स) और sys / param.h के FreeBSD संस्करणों में भी प्रदान किया गया है, और इसमें ड्रीमलैक्स द्वारा दी गई परिभाषा है।


डेबियन पर:

$ 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 पर:

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

स्रोत रिपोजिटरी यहाँ हैं:


मैंने ऊपर दिए गए मेरे उत्तर में जिन प्रणालियों का उपयोग किया है उनसे परिभाषाएँ जोड़ दी हैं (टिप्पणी क्षेत्र जहाँ तक मैं बता सकता हूँ, स्वरूपण स्वीकार नहीं करता है)। FreeBSD / Linux / glibc source repos के लिंक खोजने की कोशिश करेंगे।
मिकेल

+1। बहुत अच्छा। openSUSE/Linux 3.1.0-1.2-desktop/ के लिए gcc version 4.6.2 (SUSE Linux) भी काम करता है। :) बुरा यह पोर्टेबल नहीं है।
जैक

Cygwin पर भी काम करता है।
CMCDragonkai

1
एक पल इंतज़ार करें। यह दोहरे मूल्यांकन को नहीं रोकता है, है ना? : 3
user1857492

76

वहाँ एक है std::minऔर std::maxC ++, लेकिन AFAIK, वहाँ सी मानक पुस्तकालय में कोई समकक्ष है। आप उन्हें अपने आप को मैक्रोज़ जैसे परिभाषित कर सकते हैं

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

लेकिन यह समस्याओं का कारण बनता है अगर आप कुछ लिखते हैं MAX(++a, ++b)


10
बहुत अधिक कोष्ठक क्यों डाले ??? मुझे एक प्रश्नोत्तरी मिली जहां उन्होंने कहा कि #define MIN(A, B) ((A < B) ? A : B)एक लचीला तरीका नहीं है, क्यों ???

78
@ मकौड़ा: मैक्रो में अतिरिक्त कोष्ठक ऑपरेटर की पूर्ववर्ती समस्याओं से बचने में मदद करते हैं। उदाहरण के लिए, विचार करें #define MULT(x, y) x * y। फिर MULT(a + b, a + b)फैलता है a + b * a + b, जो a + (b * a) + bकि पूर्वगामी होने के कारण पार्स करता है। शायद यही प्रोग्रामर का इरादा था।
dan04

कि जब जरूरत नहीं है ?: वैसे भी सबसे कम पूर्वता है
विंगर सेंडोन

@WingerSendon: यह नहीं है; अल्पविराम ऑपरेटर करता है
०४

24

गैर-मानक संकलक एक्सटेंशन से बचें और इसे शुद्ध मानक C (ISO 9899: 2011) में पूरी तरह से सुरक्षित मैक्रो के रूप में लागू करें।

समाधान

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

प्रयोग

MAX(int, 2, 3)

व्याख्या

मैक्रो मैक्स typeपैरामीटर के आधार पर एक और मैक्रो बनाता है । यह नियंत्रण मैक्रो, यदि दिए गए प्रकार के लिए लागू किया जाता है, तो यह जांचने के लिए उपयोग किया जाता है कि दोनों पैरामीटर सही प्रकार के हैं। यदि typeसमर्थित नहीं है, तो संकलक त्रुटि होगी।

यदि या तो x या y सही प्रकार का नहीं है, तो ENSURE_मैक्रोज़ में संकलक त्रुटि होगी । यदि अधिक प्रकार का समर्थन किया जाता है तो अधिक मैक्रो को जोड़ा जा सकता है। मैंने मान लिया है कि केवल अंकगणित प्रकार (पूर्णांक, फ़्लोट्स, पॉइंटर्स आदि) का उपयोग किया जाएगा और न कि संरचित या बन्दी आदि।

यदि सभी प्रकार सही हैं, तो GENERIC_MAX मैक्रो कहा जाएगा। प्रत्येक मैक्रो पैरामीटर के आसपास अतिरिक्त कोष्ठक की आवश्यकता होती है, सी मैक्रोज़ लिखते समय सामान्य मानक एहतियात के रूप में।

फिर सी में निहित प्रकार के प्रचार के साथ सामान्य समस्याएं हैं। ?:ऑपरेटर एक दूसरे के खिलाफ दूसरे और तीसरे ऑपरेटर को संतुलित करता है। उदाहरण के लिए, का परिणाम GENERIC_MAX(my_char1, my_char2)होगा int। मैक्रो को इस तरह के संभावित खतरनाक प्रकार के प्रचार करने से रोकने के लिए, अंतिम प्रकार के लिए इच्छित प्रकार का उपयोग किया गया था।

दलील

हम चाहते हैं कि दोनों पैरामीटर मैक्रो के लिए एक ही प्रकार के हों। यदि उनमें से एक अलग प्रकार का है, तो मैक्रो अब सुरक्षित प्रकार नहीं है, क्योंकि एक ऑपरेटर जैसे ?:अंतर्निहित प्रकार के पदोन्नति देगा। और क्योंकि यह करता है, हमें हमेशा अंतिम परिणाम वापस करने की आवश्यकता होती है जैसा कि ऊपर बताया गया है।

केवल एक पैरामीटर के साथ एक मैक्रो को बहुत सरल तरीके से लिखा जा सकता था। लेकिन 2 या अधिक मापदंडों के साथ, एक अतिरिक्त प्रकार के पैरामीटर को शामिल करने की आवश्यकता है। क्योंकि ऐसा कुछ दुर्भाग्य से असंभव है:

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

समस्या यह है कि यदि उपरोक्त मैक्रो को MAX(1, 2)दो के साथ कहा जाता है int, तो यह अभी भी _Genericएसोसिएशन सूची के सभी संभावित परिदृश्यों को मैक्रो-विस्तारित करने का प्रयास करेगा । तो ENSURE_floatमैक्रो का विस्तार भी हो जाएगा, भले ही यह प्रासंगिक न हो int। और चूंकि मैक्रो में जानबूझकर केवल floatप्रकार होता है , कोड संकलन नहीं करेगा।

इसे हल करने के लिए, मैंने ## ऑपरेटर के साथ पूर्व-प्रोसेसर चरण के दौरान मैक्रो नाम बनाया, ताकि कोई मैक्रो गलती से विस्तारित न हो जाए।

उदाहरण

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

उस GENERIC_MAXमैक्रो का एक बुरा विचार है, आपको केवल यह GENERIC_MAX(var++, 7)पता लगाने की कोशिश करनी है कि क्यों :-) आजकल (विशेष रूप से भारी अनुकूलन / इनलाइंग कंपाइलर्स के साथ), मैक्रोज़ को केवल सरल रूपों में ही बहुत अधिक बार पुनर्प्राप्त किया जाना चाहिए। फ़ंक्शन-जैसे वाले फ़ंक्शन के रूप में बेहतर होते हैं और मान-समूह वाले एन्यूमरेशन के रूप में बेहतर होते हैं।
paxdiablo

21

मुझे नहीं लगता कि वे मानकीकृत मैक्रोज़ हैं। फ़्लोटिंग पॉइंट के लिए पहले से ही मानकीकृत फ़ंक्शन हैं, fmaxऔर fmin(और fmaxfफ़्लोट्स के लिए, और fmaxlलंबे डबल्स के लिए)।

जब तक आप साइड-इफेक्ट्स / दोहरे मूल्यांकन के मुद्दों के बारे में जानते हैं, तब तक आप उन्हें मैक्रोज़ के रूप में लागू कर सकते हैं।

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

ज्यादातर मामलों में, आप इसे यह निर्धारित करने के लिए संकलक पर छोड़ सकते हैं कि आप क्या कर रहे हैं और इसे सर्वश्रेष्ठ के रूप में अनुकूलित कर सकते हैं। जब यह समस्याओं का कारण बनता है MAX(i++, j++), जैसे कि इस्तेमाल किया जाता है , तो मुझे संदेह है कि एक बार में बढ़े हुए मूल्यों की अधिकतम जांच करने की आवश्यकता है। पहले इन्क्रीमेंट, फिर चेक।


यह पसंदीदा उत्तर होना चाहिए क्योंकि गणित पुस्तकालय में स्पष्ट रूप से न्यूनतम और अधिकतम कार्य हैं: cplusplus.com/reference/cmath/fmax
imranal

@imranal क्या आप वास्तव में क्या बोल रहे हैं? उन पुस्तकालय का कार्यान्वयन कोड? लेकिन उस कोड को उजागर नहीं किया गया है , यानी वे इसे लाइब्रेरी के इंटरफेस में नहीं रख रहे हैं, संभावित रूप से असुरक्षित है।
एंटोनियो

@Antonio मुझे लगता है कि आप "उजागर" और "इंटरफ़ेस" की गलत परिभाषाओं का उपयोग कर रहे हैं। एसी लाइब्रेरी का इंटरफ़ेस हेडर फ़ाइल में बाहरी चर, प्रकार, मैक्रोज़ और फ़ंक्शन घोषणाएँ हैं; हेडर फाइल में fmin / fmax को घोषित किया जाता है, इसलिए उन्हें उजागर किया जाता है। मुझे यकीन नहीं है कि आप हालांकि असुरक्षित के रूप में संदर्भित कर रहे हैं।
rationalcoder

21

यह एक हाल ही में विकास के कारण, एक देर से जवाब है। चूंकि ओपी ने गैर-पोर्टेबल जीसीसी (और क्लैंग) एक्सटेंशन पर निर्भर होने वाले जवाब को स्वीकार कर लिया है typeof- या __typeof__'क्लीन' आईएसओ सी के लिए - वहाँ एक बेहतर समाधान उपलब्ध है gcc-4.9

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

इस विस्तार का स्पष्ट लाभ यह है कि प्रत्येक मैक्रो तर्क केवल एक बार __typeof__समाधान के विपरीत विस्तारित होता है ।

__auto_typeC ++ 11 का सीमित रूप है auto। यह C ++ कोड में उपयोग नहीं किया जा सकता है (या नहीं?), हालांकि autoC ++ 11 का उपयोग करते समय बेहतर प्रकार की इंजेक्शन क्षमताओं का उपयोग नहीं करने का कोई अच्छा कारण नहीं है ।

उस ने कहा, मुझे लगता है कि मैक्रो को एक extern "C" { ... }दायरे में शामिल करने पर इस सिंटैक्स का उपयोग करने में कोई समस्या नहीं है ; जैसे, C हेडर से। AFAIK, इस एक्सटेंशन ने अपने तरीके की जानकारी नहीं ली है


ब्रेट हेल की टिप्पणी से संबंधित , 2016 के आसपास clangसमर्थन करना शुरू किया __auto_type(देखें पैच )।
लार्स

मैक्रो समस्या को पहचानने के लिए यश, लेकिन मैं अभी भी यह कहना चाहूंगा कि एक समारोह शायद बेहतर होगा :-)
paxdiablo

@paxdiablo - मैं सहमत हूं, हालांकि सवाल का c-preprocessorटैग है। जब तक gcc की __always_inline__विशेषता जैसी किसी चीज का उपयोग नहीं किया जाता है, तब तक किसी फ़ंक्शन को उक्त कीवर्ड के साथ इनलाइन किए जाने की गारंटी नहीं है ।
ब्रेट हेल

11

मैंने यह संस्करण लिखा है जो MSVC, GCC, C, और 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

मैंने अपवित्र किया लेकिन अपरकेस अक्षर द्वारा निम्नलिखित अंडरस्कोर के साथ शुरुआत करने वाले पहचानकर्ता आरक्षित हैं।
ड्रीमलैक्स

8

यदि आपको एक महंगी शाखा से बचने के लिए न्यूनतम / अधिकतम की आवश्यकता है, तो आपको टर्नरी ऑपरेटर का उपयोग नहीं करना चाहिए, क्योंकि यह एक छलांग के लिए संकलित होगा। नीचे दिए गए लिंक में ब्रांचिंग के बिना मिनट / अधिकतम फ़ंक्शन को लागू करने के लिए एक उपयोगी विधि का वर्णन किया गया है।

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


1
यदि कंपाइलर काफी स्मार्ट है तो वह शाखा से बच सकता है
एक्सल गेनिटिंग

2
यदि अनुकूलन चालू होता है, तो सभी आधुनिक संकलक ज्यादातर मामलों में एक शाखा के बजाय एक सशर्त चाल का उत्सर्जन करेंगे, इसलिए इस तरह से हैक का उपयोग करने का बहुत कम बिंदु है।
Krzysztof कोसीस्की

1
बिल्कुल सच है, मुझे पता नहीं है कि मैं क्या देख रहा था फिर, यह एक समय हो गया है। दोनों gcc और clang -O के साथ शाखाओं से बचते हैं, दोनों x86 और armv7a पर।
14

6

@ दाविद टिटारेंको ने यहां पर इसे बंद कर दिया , लेकिन मुझे कम से कम इसे साफ करने के लिए थोड़ा साफ करने दें, और यहां से नकल और चिपकाने को आसान बनाने के लिए दोनों min() को max() एक साथ दिखाएं । :)

25 अप्रैल 2020 को अपडेट करें: मैंने यह दिखाने के लिए कि यह कैसे C ++ टेम्पलेट के साथ भी किया जाएगा, धारा 3 को जोड़ा है, C और C ++ दोनों को सीखने वालों के लिए एक मूल्यवान तुलना के रूप में, या एक से दूसरे में संक्रमण करना। मैंने पूरी कोशिश की है कि मैं पूरी तरह से तथ्यात्मक और सही साबित होऊं और इस जवाब को एक विवादास्पद संदर्भ बनाऊं जो मैं बार-बार वापस आ सकता हूं, और मुझे उम्मीद है कि आप इसे मेरे लिए उतना ही उपयोगी पाएंगे।

1. पुराने सी मैक्रो तरीका:

इस तकनीक का आमतौर पर उपयोग किया जाता है, अच्छी तरह से उन लोगों द्वारा सम्मानित किया जाता है जो इसे ठीक से उपयोग करना जानते हैं, चीजों को करने का "वास्तविक" तरीका है, और अगर ठीक से उपयोग किया जाता है, तो ठीक है, लेकिन छोटी गाड़ी (सोचें: दोहरे मूल्यांकन के दुष्प्रभाव ) यदि आप तुलना करने के लिए चर असाइनमेंट सहित कभी भी अभिव्यक्तियाँ :

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

2. नया और बेहतर gcc " कथन अभिव्यक्ति " तरीका:

यह तकनीक उपरोक्त "दोहरे-मूल्यांकन" दुष्प्रभावों और बग से बचा जाता है, और इसलिए इसे बेहतर, सुरक्षित और "अधिक आधुनिक" जीसीसी सी तरीका माना जाता है । यह अपेक्षा करें कि दोनों gcc और clang संकलक के साथ काम करें, क्योंकि clang है, डिज़ाइन द्वारा, gcc- संगत (इस उत्तर के निचले भाग में clang नोट देखें)।

लेकिन: " वैरिएबल शैडोइंग " इफेक्ट्स को अभी भी देखें, क्योंकि स्टेटमेंट एक्सप्रेशंस जाहिरा तौर पर इनबिल्ट हैं और इसलिए उनका अपना वैरिएबल स्कोप स्कोप नहीं है!

#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 स्टेटमेंट एक्सप्रेशन में, कोड ब्लॉक में अंतिम एक्सप्रेशन है जो कि एक्सप्रेशन से "वापस" है, जैसे कि इसे किसी फंक्शन से लौटाया गया हो। जीसीसी के प्रलेखन यह इस तरह कहते हैं:

यौगिक कथन में अंतिम चीज एक अभिव्यक्ति होनी चाहिए जिसके बाद अर्धविराम होता है; इस उपसंचाई का मान पूरे निर्माण के मूल्य के रूप में कार्य करता है। (यदि आप ब्रेसिज़ के भीतर किसी अन्य प्रकार के कथन का उपयोग करते हैं, तो निर्माण में टाइप शून्य है, और इस प्रकार प्रभावी रूप से कोई मूल्य नहीं है)

3. सी ++ टेम्पलेट तरीका:

C ++ नोट: यदि C ++ का उपयोग किया जाता है, तो इस प्रकार के निर्माण के लिए संभवतः टेम्पलेट्स की सिफारिश की जाती है, लेकिन मैं व्यक्तिगत रूप से टेम्पलेट्स को नापसंद करता हूं और संभवतः C ++ में उपरोक्त निर्माणों में से एक का उपयोग करेगा, जैसा कि मैं अक्सर उपयोग करता हूं और एम्बेडेड C ++ में C शैलियों को भी पसंद करता हूं।

इस खंड में 25 अप्रैल 2020 जोड़ा गया:

मैं पिछले कुछ महीनों से C ++ का एक टन कर रहा हूं, और मैक्रो पर टेम्पलेट पसंद करने का दबाव, जहां C ++ समुदाय में सक्षम है, काफी मजबूत है। नतीजतन, मैं टेम्प्लेट का उपयोग करने में बेहतर हो रहा हूं, और पूर्णता के लिए यहां C ++ टेम्प्लेट संस्करणों में रखना चाहता हूं और इसे अधिक विहित और पूरी तरह से उत्तर देना चाहता हूं।

यहाँ क्या मूल फ़ंक्शन टेम्पलेट संस्करण हैं max()और min()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;
}

C ++ टेम्प्लेट के बारे में यहाँ अतिरिक्त रीडिंग करें: विकिपीडिया: टेम्प्लेट (C ++)

हालांकि, दोनों max()और min()पहले से ही सी ++ मानक पुस्तकालय का हिस्सा है, में हैं <algorithm>हैडर ( #include <algorithm>)। C ++ मानक पुस्तकालय में वे मेरे द्वारा ऊपर की तुलना में थोड़ा अलग तरीके से परिभाषित किए गए हैं। के लिए डिफ़ॉल्ट प्रोटोटाइप std::max<>()और std::min<>(), उदाहरण के लिए, सी ++ 14 में, बस ऊपर cplusplus.com लिंक में अपने प्रोटोटाइप को देखते हुए, इस प्रकार हैं:

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

ध्यान दें कि कीवर्ड typenameको किसी अन्य नाम है class(ताकि उनके उपयोग समान है कि क्या आप कहते हैं कि <typename T>या <class T>), क्योंकि यह बाद में सी ++ टेम्पलेट्स के आविष्कार के बाद स्वीकार किया गया था, कि टेम्पलेट प्रकार एक नियमित प्रकार हो सकता है ( int, floatआदि) केवल के बजाय एक वर्ग प्रकार।

यहां आप देख सकते हैं कि दोनों इनपुट प्रकार, साथ ही रिटर्न प्रकार, हैं const T&, जिसका अर्थ है "टाइप करने के लिए निरंतर संदर्भ T"। इसका मतलब है कि इनपुट पैरामीटर्स और रिटर्न वैल्यू को पास किए गए मान के बजाय संदर्भ द्वारा पास किया जाता है । यह पॉइंटर्स से गुजरने जैसा है, और बड़े प्रकारों के लिए अधिक कुशल है, जैसे कि क्लास ऑब्जेक्ट। constexprफ़ंक्शन का हिस्सा स्वयं फ़ंक्शन को संशोधित करता है और इंगित करता है कि फ़ंक्शन का संकलन-समय (कम से कम यदि इनपुट पैरामीटर प्रदान किया गया है ) पर मूल्यांकन करने में सक्षम होना चाहिएconstexpr , लेकिन यदि संकलन-समय पर इसका मूल्यांकन नहीं किया जा सकता है, तो यह वापस डिफॉल्ट करता है रन-टाइम मूल्यांकन, किसी अन्य सामान्य कार्य की तरह।

constexprC ++ फ़ंक्शन का संकलन-समय पहलू इसे C-मैक्रो-की तरह बनाता है, जिसमें यदि किसी constexprफ़ंक्शन के लिए संकलन-समय का मूल्यांकन संभव है , तो यह संकलन-समय पर किया जाएगा, जैसे कि MIN()या MAX()मैक्रो प्रतिस्थापन संभव हो सकता है C या C ++ में भी संकलन-समय पर पूरी तरह से मूल्यांकन किया जाए। इस C ++ टेम्पलेट जानकारी के लिए अतिरिक्त संदर्भ के लिए, नीचे देखें।

संदर्भ:

  1. https://gcc.gnu.org/onlinedocs/gcc/Typeof.html#Typeof
  2. https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
  3. C में MIN और MAX
  4. अतिरिक्त C ++ टेम्प्लेट संदर्भों ने अप्रैल 2020 जोड़ा:
    1. ***** विकिपीडिया: टेम्पलेट (C ++) <- C ++ टेम्पलेट के बारे में अतिरिक्त जानकारी!
    2. (मेरा अपना प्रश्न और उत्तर): `constexpr` का हिस्सा C ++ 14 टेम्पलेट प्रोटोटाइप के लिए` std :: max () `का हिस्सा क्यों है?
    3. `Constexpr` और` const` के बीच अंतर

क्ले नोट विकिपीडिया से :

[Clang] को GNU कंपाइलर कलेक्शन (GCC) के लिए ड्रॉप-इन रिप्लेसमेंट के रूप में कार्य करने के लिए डिज़ाइन किया गया है, जो इसके अधिकांश संकलन झंडे और अनौपचारिक भाषा एक्सटेंशन का समर्थन करता है।


पिछले 24 घंटे से डाउनवॉटर करने के लिए: अच्छी खबर है! मैंने कल अपनी धारा 4 शेख़ी को हटा दिया है जिसे मैंने कल धारा 3 के साथ जोड़ा था, और मैंने इसे यहाँ रखा है । मेरे जवाब का पुनर्मूल्यांकन करने के लिए आपका स्वागत है और यदि आप चाहें तो इसे आगे बढ़ाएं, क्योंकि मैंने इसमें बहुत सारी अच्छी जानकारी दी है और सभी को लाभ पहुंचाने के लिए इसे ठोस, उपयोगी, विहित उत्तर देने की पूरी कोशिश की है। यह अब वापस ध्यान केंद्रित किया जा रहा है। :) धन्यवाद!
गेब्रियल स्टेपल्स 19

4

यह इंगित करने योग्य है कि मुझे लगता है कि यदि आप परिभाषित करते हैं minऔर maxतृतीयक के साथ जैसे कि

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

तब के विशेष मामले के लिए एक ही परिणाम प्राप्त करने के लिए fmin(-0.0,0.0)और fmax(-0.0,0.0)आपको तर्कों को स्वैप करने की आवश्यकता है

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

फिर भी NaN के लिए काम नहीं करेगा। fmin(3.0,NaN)==fmin(NaN,3.0)==fmax(3.0,NaN)==fmax(NaN,3.0)==3.0
greggo

@greggo, मैंने यहां एक बेहतर जवाब दिया stackoverflow.com/a/30915238/2542702
Z boson

4

लगता है Windef.h(एक ला #include <windows.h>) के पास maxऔर min(निचला मामला) मैक्रोज़ है, जो "दोहरे मूल्यांकन" की कठिनाई से भी पीड़ित हैं, लेकिन वे उन लोगों के लिए हैं जो अपने स्वयं के पुन: रोल नहीं करना चाहते हैं :)


12
क्या आप भी हैरान हैं?
मैट जॉइनर

2

मुझे पता है कि आदमी ने कहा "C" ... लेकिन अगर आपके पास मौका है, तो C ++ टेम्पलेट का उपयोग करें:

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

सुरक्षित टाइप करें, और अन्य टिप्पणियों में उल्लिखित ++ के साथ कोई समस्या नहीं है।


16
तर्क को संदर्भ होना चाहिए, आप कभी नहीं जानते कि उपयोगकर्ता क्या पारित करेगा।
nmikhailov

6
इस तरह के एक समारोह पहले से ही मानकीकृत किया गया है ( std :: min )।
ड्रीमलैक्स

C ++ में अधिकांश सामान्य उद्देश्यों के लिए बहुत सारे मानक कार्य हैं, पहिया को फिर से मजबूत न करें। हालाँकि MS अपने स्वयं के न्यूनतम / अधिकतम को भी परिभाषित करता है जो कभी-कभी समस्या का कारण बनता है
phuclv

0

अधिकतम दो पूर्णांक aऔर bहै (int)(0.5((a+b)+abs(a-b)))। यह भी साथ काम कर सकते (double)हैं और fabs(a-b)युगल के लिए (तैरता के लिए समान)


क्षमा करें यदि यह गलत है, तो मैं एक सी शुरुआत हूं लेकिन यह कोड मेरे लिए काम करता है
NRZ

2
मुझे यकीन नहीं है कि यह गैर पूर्णांक के साथ काम करता है। फ्लोटिंग पॉइंट मैथ में नॉनलाइनियर प्रिसेंस है।
ट्रीसुर्ले 14

@ Treesrule14 की टिप्पणी पर विस्तार करने के लिए: यह काम नहीं करता है क्योंकि कंप्यूटर गणितज्ञों के समान संख्याओं का इलाज नहीं करते हैं। फ़्लोटिंग पॉइंट में गोलाई मुद्दे हैं, इसलिए आपको सही उत्तर प्राप्त होने की संभावना नहीं होगी। यदि आप पूर्णांक गणित का उपयोग करते हैं, तो भी MAX_INT + MAX_INT -2 देता है, इसलिए आपके सूत्र का उपयोग करके अधिकतम (MAX_INT, MAX_INT) -1 के रूप में सामने आएगा।
user9876

-3

सबसे सरल तरीका यह है कि इसे एक .hफ़ाइल में एक वैश्विक फ़ंक्शन के रूप में परिभाषित किया जाए , और जब चाहें तब इसे कॉल करें, यदि आपका प्रोग्राम बहुत सारी फ़ाइलों के साथ मॉड्यूलर है। यदि नहीं, double MIN(a,b){return (a<b?a:b)}तो सबसे सरल तरीका है।


1
@technosaurus यह मददगार होगा यदि आपने बताया कि यह समाधान गलत क्यों है, न कि केवल यह।
Tur1ng

@technosaurus, आपकी प्रतिक्रिया वास्तव में अनपेक्षित है। Tur1ing, ऐसा प्रतीत होता है कि फ़ंक्शन पूरी तरह से गलत है (इनपुट पार्म्स पर लापता प्रकार, रिटर्न स्टेटमेंट के बाद अर्धविराम गायब है), और इंट इनपुट को डबल में परिवर्तित करना चीजों को करने का एक खराब तरीका है, इसलिए टाइप डबल नहीं होना चाहिए। एक परिभाषित या कथन की अभिव्यक्ति यहाँ बेहतर होगी (उदा: यहाँ देखें ), लेकिन यदि कोई फ़ंक्शन, int32_t प्रकारों के लिए ऐसा करने के लिए एक फ़ंक्शन बनाने पर विचार करें, एक uint32_t प्रकारों के लिए, और एक फ्लोट या डबल प्रकारों के लिए, कुल 3 के लिए विभिन्न कार्यों।
गेब्रियल स्टेपल्स

1
@GabrielStaples इस उत्तर को एक उत्तर के रूप में चिह्नित किया जाना चाहिए - इसमें कोई मदद नहीं है। यद्यपि इसका उपयोग इस उदाहरण के रूप में किया जा सकता है कि अंतरिक्ष की सबसे छोटी राशि में सबसे गलत कैसे हो। हेडर में वैश्विक कार्यों की सिफारिश करना (स्थिर इनलाइन भी नहीं?) 2 + संकलन इकाइयों के साथ कोड को तोड़ देगा, संकलन भी नहीं करता है, एक मैक्रो की तरह एक फ़ंक्शन का नामकरण, इसके 1989 की तरह ints निहित है, बिना किसी कारण के लिए एक डबल लौटा, निहित। सबसे अच्छे तरीके से चेतावनियों का कारण बनेगा ... और सबसे महत्वपूर्ण बात यह है कि प्रश्न - सामान्य नहीं, प्रकार-सुरक्षित नहीं और निश्चित रूप से सबसे अच्छा तरीका नहीं है
टेक्नोकोरस

उन समस्याओं में से प्रत्येक आगे की आलोचना के पात्र हैं जिन्हें पर्याप्त विस्तार से कवर नहीं किया जा सकता है।
टेक्नोसॉरस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.