মিন এবং ম্যাক্স সি তে


298

সি MINএবং কোথায় MAXসংজ্ঞায়িত করা হয়, যদি আদৌ?

এগুলি বাস্তবায়নের সর্বোত্তম উপায় কোনটি, সাধারণভাবে এবং যথাসম্ভব নিরাপদে টাইপ করুন? (মূলধারার সংকলকগুলির জন্য সংকলক বর্ধিতকরণ / বিল্টিনগুলি পছন্দসই))

উত্তর:


392

সি 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
আপনি জানেন, জিসিসি-র লাইনের সাথে একটি সতর্কতা থাকলে: warning: expression with side-effects multiply evaluated by macroব্যবহারের জায়গায় ...
ক্যাফে

23
@ ক্যাফ: প্রিপ্রসেসরটির সি সিট্যাক্স সম্পর্কে আরও জটিল জ্ঞান থাকা দরকার নেই?
ড্রিমলাক্স

3
অনেকটা বের করার চেষ্টা করার পরেও, ভিসি ++ এ এটি করার মতো কোনও উপায় নেই বলে আমি মনে করি না, তবে এমএসভিসি ++ ২০১০ এর নতুন decltypeকীওয়ার্ডের সাথে গোলযোগ করার চেষ্টা করা আপনার সেরা সেরা - তবে তবুও ভিজ্যুয়াল স্টুডিও ম্যাক্রোগুলিতে যৌগিক বিবৃতি দিতে পারে না (এবং decltypeযাইহোক সি ++ হয়), অর্থাত্ জিসিসির ({ ... })সিনট্যাক্স তাই আমি নিশ্চিত যে এটি কোনওভাবেই সম্ভব নয়। আমি এই সমস্যা সম্পর্কিত অন্য কোনও সংকলকের দিকে নজর
দিইনি

7
@ ড্রিমলাক্স আমি একবার এমন কেস দেখলাম যেখানে কেউ MAX(someUpperBound, someRandomFunction())এলোমেলো মানকে কিছু উচ্চ স্তরের সীমাবদ্ধ করার জন্য করেছিল। এটি একটি ভয়ানক ধারণা ছিল, তবে এটি এমনকি কার্যকরও হয়নি, কারণ MAXতিনি যে ব্যবহার করছিলেন তার দ্বিগুণ মূল্যায়নের সমস্যা ছিল, তাই প্রাথমিকভাবে যা মূল্যায়ন করা হয়েছিল তার চেয়ে আলাদা এলোমেলো সংখ্যার সাথে তিনি শেষ করেছেন।
জেভ আইজেনবার্গ

8
@ সৌমেন উদাহরণস্বরূপ, আপনি যদি কল করেন MIN(x++, y++)তবে প্রিপ্রসেসর নীচের কোডটি উত্পন্ন করবে (((x++) < (y++)) ? (x++) : (y++))। সুতরাং, xএবং yদুবার বৃদ্ধি করা হবে।
অ্যান্টোনিও

91

এটি জিএনইউ লিবিসি (লিনাক্স) এবং সায়স / প্যারাম এইচএস এর ফ্রিবিএসডি সংস্করণগুলিতেও সরবরাহ করা হয়েছে এবং স্বপ্নাদলক্ষীর দ্বারা সরবরাহ করা সংজ্ঞা রয়েছে।


দেবিয়ান:

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

ফ্রিবিএসডি তে:

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

উত্স সংগ্রহস্থলগুলি এখানে রয়েছে:


উপরের আমার উত্তরে আমার যে সিস্টেমে অ্যাক্সেস রয়েছে সেগুলি থেকে আমি সংজ্ঞাগুলি যুক্ত করেছি (মন্তব্য ক্ষেত্রটি যতদূর আমি বলতে পারি বিন্যাস গ্রহণ করে না)। ফ্রিবিএসডি / লিনাক্স / গ্লিবসি উত্স রেপোগুলির লিঙ্কগুলি সন্ধান করার চেষ্টা করবে।
মাইকেল

+1 টি। খুব সুন্দর. openSUSE/Linux 3.1.0-1.2-desktop/ gcc version 4.6.2 (SUSE Linux) খুব জন্য কাজ করে। :) খারাপ এটি পোর্টেবল নয়।
জ্যাক

সাইগউইনের উপরও কাজ করে।
সিএমসিডিগ্রাগনকাই

1
একটু অপেক্ষা করো. এটি দ্বিগুণ মূল্যায়ন রোধ করে না, তাই না? : 3
ব্যবহারকারী 1857492

76

সি ++ তে একটি std::minএবং std::maxআছে, কিন্তু আফাইক, সি স্ট্যান্ডার্ড লাইব্রেরিতে কোনও সমতুল্য নেই। এগুলি আপনি ম্যাক্রোগুলির মতো নিজের সাথে সংজ্ঞায়িত করতে পারেন

#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

কখন দরকার নেই
?:

@ উইঙ্গারসেন্ডন: এটি হয় না; কমা অপারেটর করে।
dan04

24

অ-মানক সংকলক এক্সটেনশনগুলি এড়িয়ে চলুন এবং খাঁটি স্ট্যান্ডার্ড সি (আইএসও 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 ম্যাক্রো কল করা হবে। প্রতিটি ম্যাক্রো প্যারামিটারের চারপাশে অতিরিক্ত প্রথম বন্ধনী প্রয়োজন, সি ম্যাক্রো লেখার সময় সাধারণ মানক সতর্কতা হিসাবে।

তারপরে সিটিতে অন্তর্নিহিত ধরণের প্রচারের ক্ষেত্রে স্বাভাবিক সমস্যা রয়েছে ?:অপারেটর একে অপরের বিপরীতে 2 য় এবং 3 য় অপারেন্ডকে ভারসাম্যপূর্ণ করে। উদাহরণস্বরূপ, ফলাফল 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++), তখন আমি সন্দেহ করি যে একবারে সর্বাধিক বর্ধিত মানগুলি পরীক্ষা করার জন্য খুব বেশি প্রয়োজন আছে। প্রথমে বৃদ্ধি, তারপরে চেক করুন।



@ মিমরনাল আপনি ঠিক কী সম্পর্কে বলছেন? বাস্তবায়ন ঐ লাইব্রেরির কোড? তবে সেই কোডটি উন্মোচিত হয় না , অর্থাৎ তারা এটি সম্ভাব্য অনিরাপদ হয়ে লাইব্রেরির ইন্টারফেসে রাখছে না।
আন্তোনিও

@ অ্যান্টোনিও আমি মনে করি আপনি "এক্সপোজড" এবং "ইন্টারফেস" এর ভুল সংজ্ঞা ব্যবহার করছেন। এসি লাইব্রেরির ইন্টারফেস হ'ল হেডার ফাইলে বহিরাগত ভেরিয়েবল, প্রকার, ম্যাক্রো এবং ফাংশন ডিক্লেয়ারেশন; fmin / fmax শিরোনাম ফাইলটিতে ঘোষিত হয়, তাই সেগুলি প্রকাশিত হবে বলে জানা যায়। আপনি কী অনিরাপদ হিসাবে উল্লেখ করছেন তা আমি নিশ্চিত নই।
যৌক্তিক

21

মোটামুটি সাম্প্রতিক বিকাশের কারণে এটি একটি দেরিতে উত্তর। যেহেতু ওপি উত্তরটি কোনও বহনযোগ্য জিসিসি (এবং ঝনঝন) এক্সটেনশনের উপর নির্ভর করে typeof- বা __typeof__'ক্লিন' আইএসও সি-র জন্য গ্রহণ করেছে - জিসিসি -৪.৯-এর মতো আরও ভাল সমাধান পাওয়া যায় ।

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

এই এক্সটেনশনের সুস্পষ্ট সুবিধা হ'ল __typeof__সমাধানের বিপরীতে প্রতিটি ম্যাক্রো যুক্তি কেবল একবার প্রসারিত হয় ।

__auto_typeসি ++ 11 এর একটি সীমাবদ্ধ ফর্ম auto। এটি সি (+ না হওয়া উচিত?) সি ++ কোডে ব্যবহার করা যাবে না, যদিও autoসি ++ 11 ব্যবহারের ক্ষেত্রে উচ্চতর প্রকারের অনুমানের ক্ষমতাগুলি ব্যবহার না করার কোনও ভাল কারণ নেই ।

এটি বলেছিল, আমি ধরে নিয়েছি যে ম্যাক্রো কোনও extern "C" { ... }সুযোগে অন্তর্ভুক্ত করার সময় এই সিনট্যাক্সটি ব্যবহার করার কোনও সমস্যা নেই ; যেমন, একটি সি শিরোনাম থেকে। আফাইক, এই এক্সটেনশানটি তার উপায় তথ্য বিড়ম্বনা খুঁজে পায় নি


সম্পর্কে ব্রেট হালে এর মন্তব্য , clangসমর্থনকারী শুরু __auto_type(দেখুন কাছাকাছি 2016 প্যাচ )।
লার্স

ম্যাক্রো সমস্যাটি স্বীকৃতি দেওয়ার জন্য
কুডোস

@ প্যাক্সিয়াব্লো - আমি সম্মত, যদিও প্রশ্নের c-preprocessorট্যাগ রয়েছে। জিসিসির __always_inline__বৈশিষ্ট্যের মতো কিছু ব্যবহার না করা পর্যন্ত কোনও ক্রিয়াকলাপটি কথ্য কীওয়ার্ডের সাথেও অন্তর্ভুক্ত হওয়ার নিশ্চয়তা নেই ।
ব্রেট হেল

11

আমি এই সংস্করণটি লিখেছি যা এমএসভিসি, জিসিসি, সি, এবং সি ++ এর জন্য কাজ করে।

#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



2
যদি অপ্টিমাইজেশন চালু থাকে, তবে সমস্ত আধুনিক সংকলক বেশিরভাগ ক্ষেত্রে শাখার পরিবর্তে শর্তসাপেক্ষ পদক্ষেপের প্রেরণ করবে, তাই হ্যাকগুলি ব্যবহার করার মতো সামান্য বিষয় রয়েছে।
Krzysztof Kosiński

1
একদম সত্য, আমি তখন পিছনে কী দেখছিলাম সে সম্পর্কে আমার কোনও ধারণা নেই, কিছুক্ষণ হয়ে গেল। জিসিসি এবং ঝনঝন উভয়ই x86 এবং আর্মভ 7 এ--এর শাখা এড়াতে পারে।
সিবি

6

@ ডেভিড টাইটারেনসো এটি এখানে পেরেক দিয়েছিলেন , তবে এটিকে সুন্দর দেখানোর জন্য আমাকে কমপক্ষে এটি পরিষ্কার করতে দিন এবং এখান থেকে অনুলিপি এবং আটকানো সহজ করার জন্য উভয়কে min() এবং max() একসাথে দেখান । :)

আপডেট 25 এপ্রিল 2020: সি এবং সি ++ উভয় শেখার জন্য বা এক থেকে অন্যটিতে রূপান্তরকারীদের জন্য মূল্যবান তুলনা হিসাবে, আমি কীভাবে সি ++ টেম্পলেটগুলির সাথে এটি কীভাবে করা হবে তা দেখানোর জন্য আমি একটি বিভাগ 3 যুক্ত করেছি। আমি এই উত্তরটি বারবার ফিরে আসতে পারলাম এমন একটি প্রচলিত রেফারেন্স তৈরির জন্য পুরোপুরি এবং সত্যবাদী এবং সঠিক হওয়ার জন্য যথাসাধ্য চেষ্টা করেছি এবং আমি আশা করি আপনি এটি আমার মতো কার্যকর পেয়েছেন।

1. পুরানো সি ম্যাক্রো উপায়:

এই কৌশলটি সাধারণত ব্যবহৃত হয়, যারা সঠিকভাবে এটি কীভাবে ব্যবহার করতে জানে, "ডি ফ্যাক্টো" জিনিসগুলি করার পদ্ধতি এবং সঠিকভাবে যদি ব্যবহার করা হয় তবে সঠিকভাবে ব্যবহার করা ভাল, তবে আপনি বগি (মনে করুন: ডাবল-মূল্যায়ন পার্শ্ব প্রতিক্রিয়া ) যদি আপনি ব্যবহার করেন তবে তুলনা করতে ভেরিয়েবল অ্যাসাইনমেন্ট সহ এক্সপ্রেশনগুলি সর্বদা পাস করুন:

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

2. নতুন এবং উন্নত জিসিসি " স্টেটমেন্ট এক্সপ্রেশন " উপায়:

এই কৌশলটি উপরের "ডাবল-মূল্যায়ন" পার্শ্ব প্রতিক্রিয়া এবং বাগগুলি এড়িয়ে চলে এবং তাই এটি করার জন্য সেরা, নিরাপদ এবং "আরও আধুনিক" জিসিসি সি উপায় হিসাবে বিবেচিত হয় । এটি জিসিসি এবং ক্ল্যাং সংকলক উভয়ের সাথেই কাজ করার প্রত্যাশা করুন, যেহেতু ক্ল্যাংটি ডিজাইনের মাধ্যমে, জিসিসি-সামঞ্জস্যপূর্ণ (এই উত্তরের নীচে ক্ল্যাং নোটটি দেখুন)।

বাট: "নজর রাখুন" চলক ছায়াময় " প্রভাবগুলি এখনও , কারণ বিবৃতি প্রকাশগুলি স্পষ্টতই অন্তর্নিহিত রয়েছে এবং সেইজন্য তাদের নিজস্ব স্থানীয় পরিবর্তনশীল সুযোগ নেই!

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

নোট করুন যে সিসি স্টেটমেন্ট এক্সপ্রেশনগুলিতে কোড ব্লকের সর্বশেষ এক্সপ্রেশনটি হ'ল এক্সপ্রেশন থেকে "ফিরে", যেন এটি কোনও ফাংশন থেকে ফিরে এসেছে।জিসিসির ডকুমেন্টেশন এটিকে এভাবে বলে:

যৌগিক বিবৃতিতে শেষ জিনিসটি সেমিকোলন দ্বারা অনুসরণ করা একটি অভিব্যক্তি হওয়া উচিত; এই subexpression এর মান পুরো কনস্ট্রাক্টের মান হিসাবে কাজ করে। (যদি আপনি বন্ধনীগুলির মধ্যে শেষ পর্যন্ত অন্য কোনও ধরণের বিবৃতি ব্যবহার করেন তবে কনস্ট্রাক্টের টাইপটি বাতিল শূন্য রয়েছে এবং ফলস্বরূপ কার্যকরভাবে কোনও মূল্য নেই))

3. সি ++ টেম্পলেট উপায়:

সি ++ দ্রষ্টব্য: যদি সি ++ ব্যবহার করেন তবে পরিবর্তে এই ধরণের নির্মাণের জন্য টেমপ্লেটগুলি সম্ভবত সুপারিশ করা হয়, তবে আমি ব্যক্তিগতভাবে টেম্পলেটগুলি অপছন্দ করি এবং সম্ভবত সি ++ তে উপরের একটি নির্মাণ ব্যবহার করব, কারণ আমি প্রায়শই এম্বেড থাকা সি ++ তেও সি স্টাইলগুলি পছন্দ করি এবং পছন্দ করি।

এই বিভাগে 25 এপ্রিল যোগ করা হয়েছে 2020:

আমি গত কয়েক মাস ধরে একটি টন সি ++ করছি এবং সি ++ সম্প্রদায়ের যেখানে ম্যাক্রোগুলির তুলনায় টেমপ্লেটগুলি পছন্দ করার চাপ রয়েছে তা বেশ শক্তিশালী। ফলস্বরূপ, আমি টেমপ্লেটগুলি ব্যবহার করে আরও ভাল হয়ে উঠছি এবং সম্পূর্ণতার জন্য এখানে সি ++ টেম্পলেট সংস্করণগুলি যুক্ত করতে চাই এবং এটি আরও যুক্তিযুক্ত এবং পুঙ্খানুপুঙ্খ উত্তর করতে চাই।

এখানে কি মৌলিক এর ফাংশন টেমপ্লেট সংস্করণ 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;
}

সি ++ টেম্পলেট সম্পর্কে এখানে অতিরিক্ত পাঠ করুন: উইকিপিডিয়া: টেমপ্লেট (সি ++)

যাইহোক, উভয়ই max()এবং min()ইতিমধ্যে <algorithm>হেডারে ( #include <algorithm>) , সি ++ স্ট্যান্ডার্ড লাইব্রেরির অংশ । সি ++ স্ট্যান্ডার্ড লাইব্রেরিতে এগুলি আমার উপরের তুলনায় কিছুটা আলাদাভাবে সংজ্ঞায়িত করা হয়েছে। ডিফল্ট এগুলির নমুনা 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 ইনপুট প্যারামিটার), কিন্তু যদি এটা কম্পাইল-সময়ে মূল্যায়ন করা যাবে না, তাহলে এটি অক্ষমতা একটি ফিরে রান-টাইম মূল্যায়ন, অন্যান্য সাধারণ ফাংশনের মতো।

একটি constexprসি ++ ফাংশনের সংকলন-সময় দিকটি এটিকে সি-ম্যাক্রোর মতো করে তোলে, যদি কোনও constexprফাংশনের জন্য যদি সংকলন-সময় মূল্যায়ন সম্ভব হয় তবে এটি সংকলন-সময়ে করা হবে, একই MIN()বা একই হিসাবেMAX() ম্যাক্রো প্রতিকল্পন সম্ভবত পারা সি বা সি ++ তেও কমপাইল সময়ে সম্পূর্ণ মূল্যায়ন করা হবে। এই সি ++ টেম্পলেট তথ্যের জন্য অতিরিক্ত রেফারেন্সের জন্য, নীচে দেখুন।

তথ্যসূত্র:

  1. https://gcc.gnu.org/onlinedocs/gcc/Typeof.html#Typeof
  2. https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs
  3. মিন এবং ম্যাক্স সি তে
  4. অতিরিক্ত সি ++ টেম্পলেট রেফারেন্স এপ্রিল 2020 যুক্ত হয়েছে:
    1. ***** উইকিপিডিয়া: টেমপ্লেট (সি ++) <- সি ++ টেম্পলেট সম্পর্কে দুর্দান্ত তথ্য!
    2. (আমার নিজের প্রশ্ন ও উত্তর): Why স্ট্যান্ড :: সর্বোচ্চ () `এর জন্য কেন C ++ 14 টেমপ্লেট প্রোটোটাইপের` কনটেক্সপ্রের অংশ?
    3. `Constexpr` এবং` কনস্টের মধ্যে পার্থক্য `

উইকিপিডিয়া থেকে কলঙ্ক নোট :

[ঝাঁকুনি] GNU সংকলক সংগ্রহের জন্য একটি ড্রপ-ইন প্রতিস্থাপন হিসাবে কাজ করার জন্য ডিজাইন করা হয়েছে (জিসিসি), এর বেশিরভাগ সংকলন পতাকা এবং বেসরকারী ভাষা বর্ধনকে সমর্থন করে।


সর্বশেষ 24 ঘন্টা থেকে ডাউনওয়োটারের কাছে: সুসংবাদ! আমি আমার সেকশন 4 রেন্ট সরিয়ে ফেলেছি গতকাল আমি ধারা 3 দিয়ে যুক্ত করেছি এবং পরিবর্তে এটি এখানে রেখেছি । আপনি আমার উত্তরটি পুনরায় মূল্যায়ন করতে এবং আপনি দয়া করে যদি এটি একটি উত্সাহ দিতে স্বাগত জানায়, আমি এর মধ্যে অনেক ভাল তথ্য রেখেছি এবং এটিকে সবার উপকারের জন্য একটি দৃ ,়, সহায়ক, ক্যানোনিকাল উত্তর দেওয়ার জন্য যথাসাধ্য চেষ্টা করেছি। এটি এখন ফোকাস করা ফিরে। :) ধন্যবাদ!
গ্যাব্রিয়েল স্টেপলস

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)

তবুও এনএএন এর পক্ষে কাজ করবে না। fmin(3.0,NaN)==fmin(NaN,3.0)==fmax(3.0,NaN)==fmax(NaN,3.0)==3.0
গ্রেগো

@greggo, আমি একটি ভাল উত্তর এখানে দিলেন stackoverflow.com/a/30915238/2542702
বোসন জেড

4

দেখে মনে হচ্ছে Windef.h(একটি লা #include <windows.h>) এর ম্যাক্রোগুলি রয়েছে maxএবং minএটি "ডাবল মূল্যায়ন" অসুবিধায় ভুগছে, তবে তারা তাদের জন্য রয়েছে যারা নিজের পুনরায় রোল করতে চান না :)


12
আপনি কি অবাক?
ম্যাট জেন্ডার 15

2

আমি জানি লোকটি "সি" বলেছিল ... তবে আপনার যদি সুযোগ হয় তবে একটি সি ++ টেম্পলেট ব্যবহার করুন:

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

নিরাপদ টাইপ করুন, এবং অন্যান্য মন্তব্যে উল্লিখিত ++ নিয়ে কোনও সমস্যা নেই।


16
যুক্তিগুলি কনস্টের রেফারেন্স হওয়া উচিত, আপনি কখনই জানেন না যে ব্যবহারকারী কী পাস করবে।
nmikhailov

6
এই জাতীয় ফাংশন ইতিমধ্যে মানক করা হয়েছে (স্ট্যান্ড :: মিনিট )।
স্বপ্ন 25

সি ++ এর বেশিরভাগ সাধারণ উদ্দেশ্যে প্রচুর স্ট্যান্ডার্ড ফাংশন থাকে, চাকাটি পুনরায় উদ্ভাবন করবেন না। তবে এমএস তাদের নিজস্ব ন্যূনতম / সর্বোচ্চটিও সংজ্ঞায়িত করে যা কখনও কখনও সমস্যার কারণ হয়ে থাকে
ফুক্লভ

0

সর্বোচ্চ দুটি পূর্ণসংখ্যা aএবং bহয় (int)(0.5((a+b)+abs(a-b)))। এটি ডাবলসের সাথে (double)এবং এর জন্যও কাজ করতে পারে fabs(a-b)(ফ্লোটের জন্য একই)


দুঃখিত যদি এটি ভুল হয়, আমি সি শিক্ষানবিস তবে এই কোডটি আমার পক্ষে কাজ করে
এনআরজেড

2
আমি নিশ্চিত নই যে এটি অ-পূর্ণসংখ্যার সাথে কাজ করে। ভাসমান পয়েন্ট গণিতে অরেখার যথার্থতা রয়েছে।
Treesrule14

@ ট্রিস্রুলে ১৪ এর মন্তব্যে প্রসারিত করার জন্য: এটি কাজ করে না কারণ কম্পিউটারগুলি সংখ্যার সাথে গণিতবিদদের মতো আচরণ করে না। ভাসমান পয়েন্টে গোলাকার সমস্যা রয়েছে তাই আপনার সঠিক উত্তর পাওয়ার সম্ভাবনা কম। এমনকি আপনি যদি পূর্ণসংখ্যার গণিত ব্যবহার করেন, MAX_INT + MAX)T -2 দেয়, সুতরাং আপনার সূত্রটি ব্যবহার করে সর্বোচ্চ (MAX_INT, MAX_INT) -1 হিসাবে প্রকাশিত হবে।
ব্যবহারকারী9876

-3

সবচেয়ে সহজ উপায় হ'ল এটি কোনও .hফাইলে একটি গ্লোবাল ফাংশন হিসাবে সংজ্ঞায়িত করা এবং যখনই আপনার প্রোগ্রামটি প্রচুর ফাইলের সাথে মডিউল হয় সেটিকে কল করুন। যদি না double MIN(a,b){return (a<b?a:b)}হয় তবে সহজ উপায়।


1
@ টেকনোসৌরাস এই সমাধানটি কেন ভুল তা আপনি যদি বর্ণনা করেন তবে এটি সহায়ক হবে just
তুর1ng

@ টেকনোসরাস, আপনার প্রতিক্রিয়া সত্যিই অপ্রয়োজনীয়। টুআরিং, এটি উপস্থিত হয় যে ফাংশনটি সম্পূর্ণরূপে ভুল হিসাবে সংজ্ঞায়িত হয়েছে (ইনপুট প্যারামগুলিতে প্রকারের অনুপস্থিত, রিটার্নের বিবরণের পরে সেমিকোলন অনুপস্থিত), এবং ইনপুটগুলিকে দ্বিগুণ রূপান্তর করা জিনিসগুলি করার একটি দরিদ্র উপায়, সুতরাং প্রকারটি দ্বিগুণ হওয়া উচিত নয়। একটি সংজ্ঞায়িত বা স্টেটমেন্ট এক্সপ্রেশনটি এখানে আরও ভাল হবে (যেমন: এখানে দেখুন ), তবে যদি কোনও ফাংশন হয় তবে এটি 32 টির জন্য একটি ফাংশন তৈরির কথা বিবেচনা করুন, একটি uint32_t টাইপের জন্য এবং একটি ফ্লোট বা ডাবল প্রকারের জন্য, মোট 3 টির জন্য বিভিন্ন ফাংশন।
গ্যাব্রিয়েল স্ট্যাপলস

1
@ গ্যাব্রিয়েল স্ট্যাপলস এই উত্তরটিকে উত্তর হিসাবে চিহ্নিত করা উচিত - এটির কোনও সহায়তা নেই। যদিও এটি স্থানের স্বল্প পরিমাণে কীভাবে সবচেয়ে বেশি ভুল হতে পারে তার উদাহরণ হিসাবে ব্যবহার করা যেতে পারে। শিরোনামে বিশ্বব্যাপী ফাংশনগুলির প্রস্তাব দেওয়া (স্থির ইনলাইন এমনকি নয়?) কোডটি 2+ সংকলন ইউনিট সহ বিচ্ছিন্ন করে ফেলবে, এমনকি ম্যাক্রোর মতো কোনও ক্রিয়াকলাপের নামকরণ করবে না, সংশ্লেষ করে না, 1989 এর মতো সূচিত ints, কোনও বিবৃত কারণ ছাড়াই ডাবল ফিরিয়ে দেবে যে কাস্টগুলি সর্বোত্তমভাবে সতর্কবার্তা তৈরি করবে ... এবং সবচেয়ে গুরুত্বপূর্ণভাবে এটি জবাবটি দেয় না - জেনেরিক নয়, টাইপ-নিরাপদ নয় এবং অবশ্যই সবচেয়ে ভাল উপায় নয়
টেকনোসরাস

এই সমস্যাগুলির প্রত্যেকটিই আরও সমালোচনার দাবি রাখে যা পর্যাপ্ত বিবরণে আচ্ছাদন করা যায় না।
টেকনোসরাসটি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.