কেন ম্যাক্রোগুলিতে আপাত অর্থহীন অর্থহীন এবং যদি-অন্য বিবৃতি ব্যবহার করবেন?


787

অনেক সি / সি ++ ম্যাক্রোতে আমি ম্যাক্রোর কোডটি দেখে যা যা অর্থহীন do whileলুপের মতো মনে হয় তাতে মোড়ানো seeing এখানে উদাহরণস্বরূপ।

#define FOO(X) do { f(X); g(X); } while (0)
#define FOO(X) if (1) { f(X); g(X); } else

আমি কি করতে পারি তা দেখতে পাচ্ছি do whileনা। শুধু এটুকু বাদ দিয়ে কেন লেখেন না?

#define FOO(X) f(X); g(X)

2
অন্যটির সাথে উদাহরণের জন্য, আমি voidপ্রকারের শেষে টাইপের একটি এক্সপ্রেশন যুক্ত করব ... ((শূন্য) 0) এর মতো
ফিল 1970

1
স্মরণ করিয়ে দিতে হবে যে do whileকনস্ট্রাক্ট রিটার্ন স্টেটমেন্টের সাথে সামঞ্জস্যপূর্ণ নয়, সুতরাং if (1) { ... } else ((void)0)কনস্ট্রাক্টটির স্ট্যান্ডার্ড সি এবং জিএনইউ সি-তে আরও সুসংগত ব্যবহার রয়েছে, আপনি আমার উত্তরে বর্ণিত কনস্ট্রাক্টটিকে পছন্দ করবেন।
সিউর

উত্তর:


829

do ... whileএবং if ... elseএটা যাতে আপনার ম্যাক্রো পর একটি সেমিকোলন সবসময় একই জিনিস মানে করতে হয়। ধরা যাক আপনার দ্বিতীয় ম্যাক্রোর মতো কিছু ছিল।

#define BAR(X) f(x); g(x)

এখন আপনি যদি BAR(X);কোনও if ... elseবিবৃতি ব্যবহার করতে থাকেন , যেখানে যদি বিবৃতিটির মৃতদেহগুলি কোঁকড়ানো বন্ধনীতে আবৃত না হয় তবে আপনি একটি খারাপ অবাক হবেন।

if (corge)
  BAR(corge);
else
  gralt();

উপরের কোডটি প্রসারিত হবে

if (corge)
  f(corge); g(corge);
else
  gralt();

যা সিনথেটিকভাবে ভুল, অন্যথায় আর যদি এর সাথে যুক্ত হয় না। এটি ম্যাক্রোর মধ্যে কোঁকড়ানো ধনুর্বন্ধনীগুলিতে জিনিসগুলি মোড়ানো করতে সহায়তা করে না, কারণ ধনুর্বন্ধনীগুলির পরে একটি অর্ধিকোলন সিন্ট্যাক্টিকভাবে ভুল is

if (corge)
  {f(corge); g(corge);};
else
  gralt();

সমস্যাটি ঠিক করার দুটি উপায় রয়েছে। প্রথমটি হ'ল ম্যাক্রোর মধ্যে অভিব্যক্তিটির মতো কাজ করার ক্ষমতাকে ছিনতাই না করে মেক্রোর মধ্যে বিবৃতিগুলি ক্রমের জন্য কমা ব্যবহার করা।

#define BAR(X) f(X), g(X)

বারের উপরের সংস্করণটি নীচের BARকোডগুলিকে নিম্নলিখিতগুলির মধ্যে প্রসারিত করে, যা সিন্টেক্সিকভাবে সঠিক।

if (corge)
  f(corge), g(corge);
else
  gralt();

এটির পরিবর্তে কোডগুলির f(X)একটি জটিল জটিল বডি রয়েছে যা তার নিজের ব্লকে যাওয়ার দরকার আছে এটি ব্যবহার করে না, উদাহরণস্বরূপ স্থানীয় ভেরিয়েবলগুলি ঘোষণা করতে বলুন। সর্বাধিক সাধারণ ক্ষেত্রে সমাধানটি হ'ল do ... whileম্যাক্রোকে একটি একক বিবৃতি হিসাবে বিভ্রান্তি ছাড়াই একটি সেমিকোলন নেয় এমন কিছু ব্যবহার করা ।

#define BAR(X) do { \
  int i = f(X); \
  if (i > 4) g(i); \
} while (0)

আপনাকে ব্যবহার করতে হবে না do ... while, আপনি কিছু দিয়ে রান্নাও করতে পারবেন if ... else, যদিও এটির if ... elseঅভ্যন্তরে প্রসারিত হলে if ... elseএটি " ঝুঁকির ঝাঁকুনি " বাড়ে , যা একটি বিদ্যমান ঝোপঝাঁকির সমস্যা খুঁজে পাওয়া আরও শক্ত করে তোলে, যেমন নীচের কোডের মতো ।

if (corge)
  if (1) { f(corge); g(corge); } else;
else
  gralt();

মুল বক্তব্যটি সেমিকোলনটিকে প্রসঙ্গে ব্যবহার করা যেখানে একটি জটলা সেমিকোলন ভুল r অবশ্যই, (এবং সম্ভবত হওয়া উচিত) এই মুহূর্তে যুক্তি দেওয়া যেতে পারে যে BARম্যাক্রো নয়, প্রকৃত ফাংশন হিসাবে ঘোষণা করা ভাল ।

সংক্ষেপে, do ... whileসি প্রিপ্রসেসরগুলির ত্রুটিগুলি ঘিরে কাজ করতে পারে। যখন সি স্টাইলের গাইডরা আপনাকে সি প্রিপ্রসেসরটি ছাড়ে দেওয়ার কথা বলে, তারা এই ধরণের বিষয় নিয়ে উদ্বিগ্ন।


18
যদি, কখন এবং বিবৃতিতে সর্বদা ব্রেস ব্যবহার করার পক্ষে এটি একটি শক্ত যুক্তি না? আপনি যদি সর্বদা এটি করার একটি বিন্দুটি করেন (যেমন মিজ্রা-সি যেমন প্রয়োজন যেমন) তবে উপরে বর্ণিত সমস্যাটি চলে যায়।
স্টিভ মেলানিকফ 22

17
কমা উদাহরণ হতে হবে #define BAR(X) (f(X), g(X))অন্যথায় অপারেটর অগ্রাধিকার শব্দার্থবিজ্ঞান জগাখিচুড়ি হতে পারে।
স্টুয়ার্ট

20
@ ডেভিডফেরেঞ্জি: যদিও আপনি এবং আমি-সাড়ে চার বছর আগে আমি উভয়ই একটি ভাল বক্তব্য রেখেছি, আমাদের বাস্তব বিশ্বে থাকতে হবে। যদি না আমরা গ্যারান্টি দিতে পারি না যে ifআমাদের কোডে সমস্ত বিবৃতি, ইত্যাদি ব্রেস ব্যবহার করে, তারপরে এই জাতীয় ম্যাক্রোগুলি মোড়ানো সমস্যাগুলি এড়ানোর এক সহজ উপায়।
স্টিভ মেল্নিকফ

8
দ্রষ্টব্য: if(1) {...} else void(0)ফর্মটি do {...} while(0)ম্যাক্রোগুলির তুলনায় সুরক্ষিত যার পরামিতিগুলি ম্যাক্রো প্রসারণের অন্তর্ভুক্ত কোডগুলি কারণ এটি বিরতির আচরণকে পরিবর্তন করে না বা কীওয়ার্ডগুলি চালিয়ে যায় না। উদাহরণস্বরূপ: সংজ্ঞায়িত for (int i = 0; i < max; ++i) { MYMACRO( SomeFunc(i)==true, {break;} ) }হওয়ার সময় অপ্রত্যাশিত আচরণের কারণ হয় কারণ বিরতি ম্যাক্রোর MYMACROহ'ল #define MYMACRO(X, CODE) do { if (X) { cout << #X << endl; {CODE}; } } while (0)লুপকে ম্যাক্রো কল সাইটে লুপের পরিবর্তে প্রভাবিত করে।
ক্রিস ক্লিন

5
@ace void(0)একটি টাইপো ছিল, আমি বোঝাতে চাইছি (void)0। এবং আমি মনে করেন যে এই নেই "আর আনত" সমস্যা সমাধানের: নোটিশ সেখানে পরে কোন সেমিকোলন এর (void)0। সেক্ষেত্রে অন্য একটি ঝুঁকির সংক্রমণ if (cond) if (1) foo() else (void)0 else { /* dangling else body */ }সংকলন ত্রুটি ট্রিগার করে। এখানে এটি প্রদর্শিত
ক্রিস ক্লাইন

153

ম্যাক্রো হ'ল প্রাক-প্রসেসরটি আসল কোডে প্রেরণ করা পাঠ্যের টুকরো অনুলিপি / আটকানো হয়; ম্যাক্রোর লেখক আশা করেন যে প্রতিস্থাপনটি বৈধ কোড তৈরি করবে।

এতে সফল হওয়ার জন্য তিনটি ভাল "টিপস" রয়েছে:

ম্যাক্রোটিকে আসল কোডের মতো আচরণ করতে সহায়তা করুন

সাধারন কোডটি সাধারণত একটি আধা-কোলন দ্বারা শেষ হয়। ব্যবহারকারীর ভিউ কোডটির একটির প্রয়োজন নেই ...

doSomething(1) ;
DO_SOMETHING_ELSE(2)  // <== Hey? What's this?
doSomethingElseAgain(3) ;

এর অর্থ ব্যবহারকারী আধা কোলন অনুপস্থিত থাকলে সংকলকটি একটি ত্রুটি তৈরির প্রত্যাশা করে।

তবে আসল আসল ভাল কারণটি হ'ল কোনও এক সময় ম্যাক্রোর লেখকের ম্যাক্রোর পরিবর্তে সম্ভবত একটি খাঁটি ফাংশন (সম্ভবত অন্তর্নিহিত) করা প্রয়োজন। সুতরাং ম্যাক্রোর সত্যিকারের মতো আচরণ করা উচিত ।

সুতরাং আমাদের একটি ম্যাক্রো থাকা উচিত সেমি-কোলন প্রয়োজন।

একটি বৈধ কোড উত্পাদন করুন

Jfm3 এর উত্তরে দেখানো হয়েছে, কখনও কখনও ম্যাক্রোতে একাধিক নির্দেশ থাকে। এবং যদি ম্যক্রোটি যদি একটি বিবৃতিতে ব্যবহার করা হয় তবে এটি সমস্যাযুক্ত হবে:

if(bIsOk)
   MY_MACRO(42) ;

এই ম্যাক্রো হিসাবে প্রসারিত হতে পারে:

#define MY_MACRO(x) f(x) ; g(x)

if(bIsOk)
   f(42) ; g(42) ; // was MY_MACRO(42) ;

gফাংশনের মান নির্বিশেষে মৃত্যুদন্ড কার্যকর করা হবে bIsOk

এর অর্থ হল যে আমাদের অবশ্যই ম্যাক্রোতে একটি সুযোগ যুক্ত করতে হবে:

#define MY_MACRO(x) { f(x) ; g(x) ; }

if(bIsOk)
   { f(42) ; g(42) ; } ; // was MY_MACRO(42) ;

একটি বৈধ কোড 2 উত্পাদন করুন

ম্যাক্রো কিছু হলে:

#define MY_MACRO(x) int i = x + 1 ; f(i) ;

নিম্নলিখিত কোডটিতে আমাদের আর একটি সমস্যা হতে পারে:

void doSomething()
{
    int i = 25 ;
    MY_MACRO(32) ;
}

কারণ এটি এর প্রসারিত হবে:

void doSomething()
{
    int i = 25 ;
    int i = 32 + 1 ; f(i) ; ; // was MY_MACRO(32) ;
}

এই কোডটি অবশ্যই সংকলন করবে না। সুতরাং, আবারও, সমাধানটি একটি সুযোগ ব্যবহার করছে:

#define MY_MACRO(x) { int i = x + 1 ; f(i) ; }

void doSomething()
{
    int i = 25 ;
    { int i = 32 + 1 ; f(i) ; } ; // was MY_MACRO(32) ;
}

কোডটি আবার সঠিকভাবে আচরণ করে।

আধা-কোলন + স্কোপ ইফেক্টের সংমিশ্রণ?

এখানে একটি সি / সি ++ বুদ্ধিমান রয়েছে যা এই প্রভাবটি তৈরি করে: কর / যখন লুপ:

do
{
    // code
}
while(false) ;

কর / যখন একটি সুযোগ তৈরি করতে পারে, এইভাবে ম্যাক্রোর কোডটি encapsulate করে, এবং শেষ পর্যন্ত একটি অর্ধ-কোলন প্রয়োজন, সুতরাং কোডটির প্রয়োজনীয় কোডে প্রসারিত হয়।

বোনাস?

সি ++ সংকলকটি ডু / যখন লুপটি অপ্টিমাইজ করবে, কারণ এর পোস্ট-শর্তটি মিথ্যা হ'ল সংকলন সময়ে জানা যায়। এর অর্থ হ'ল ম্যাক্রোর মতো:

#define MY_MACRO(x)                                  \
do                                                   \
{                                                    \
    const int i = x + 1 ;                            \
    f(i) ; g(i) ;                                    \
}                                                    \
while(false)

void doSomething(bool bIsOk)
{
   int i = 25 ;

   if(bIsOk)
      MY_MACRO(42) ;

   // Etc.
}

হিসাবে সঠিকভাবে প্রসারিত হবে

void doSomething(bool bIsOk)
{
   int i = 25 ;

   if(bIsOk)
      do
      {
         const int i = 42 + 1 ; // was MY_MACRO(42) ;
         f(i) ; g(i) ;
      }
      while(false) ;

   // Etc.
}

এবং তারপরে সংকলন এবং অপ্টিমাইজ করা হয়

void doSomething(bool bIsOk)
{
   int i = 25 ;

   if(bIsOk)
   {
      f(43) ; g(43) ;
   }

   // Etc.
}

6
লক্ষ্য করুন ইনলাইন ফাংশন গন্ধে পরিবর্তন করতে ম্যাক্রো পরিবর্তন কিছু মানক পূর্বনির্ধারিত ম্যাক্রো, যেমন নিচের কোডটি শো পরিবর্তন ফাংশনটির এবং লাইন : #include <stdio.h> # define Fmacro () printf, ( "% s এর% d টি \ N", ফাংশনটির , লাইন ) ইনলাইন অকার্যকর ফিনলাইন () {প্রিন্টফ ("% s% d \ n", ফাংশন , লাইন ); main int main () {Fmacro (); Finline (); প্রত্যাবর্তন 0; } (
গা bold় পদগুলি

6
এই উত্তরটির সাথে বেশ কয়েকটি ছোটখাটো তবে সম্পূর্ণ অসম্পর্কিত সমস্যা নেই। উদাহরণস্বরূপ: void doSomething() { int i = 25 ; { int i = x + 1 ; f(i) ; } ; // was MY_MACRO(32) ; }সঠিক সম্প্রসারণ নয়; xসম্প্রসারণ হওয়া উচিত 32 আরো একটি জটিল বিষয় সম্প্রসারণ হয় কি MY_MACRO(i+7)। এবং অন্যটি হ'ল এর সম্প্রসারণ MY_MACRO(0x07 << 6)। এখানে অনেক কিছুই ভাল, তবে কিছু অবিস্মরণীয় আমি এবং অমীমাংসিত টি আছে।
জোনাথন লেফলার

@ গনুবি: আমি বলছি আপনি এখনও এখানে আছেন এবং আপনি এখনই এটি সন্ধান করেন নি: আপনি ব্যাকস্ল্যাশগুলির সাথে মন্তব্যগুলিতে \_\_LINE\_\_নক্ষত্রগুলি এবং আন্ডারস্কোরগুলি থেকে রক্ষা পেতে পারেন, তাই আপনি যদি এটি টাইপ করেন __LINE__ হিসাবে। আইএমএইচও, কোডের জন্য কোড বিন্যাস ব্যবহার করা আরও ভাল; উদাহরণস্বরূপ, __LINE__(যার জন্য কোনও বিশেষ পরিচালনার প্রয়োজন নেই)। পিএস আমি জানি না এটি 2012 সালে সত্য ছিল কিনা; তার পর থেকে তারা ইঞ্জিনে বেশ কয়েকটি উন্নতি করেছে।
স্কট

1
প্রশংসা করে যে আমার মন্তব্যটি ছয় বছর দেরিতে হয়েছে, তবে বেশিরভাগ সি সংকলকরা প্রকৃতপক্ষে ইনলাইন inlineফাংশনগুলি (মান অনুসারে অনুমোদিত) করেন না
অ্যান্ড্রু

53

@ jfm3 - আপনার প্রশ্নের একটি সুন্দর উত্তর আছে। আপনি আরও যুক্ত করতে চাইবেন যে ম্যাক্রো আইডিয়ামটি সম্ভবত আরও বেশি বিপজ্জনক (কারণ কোনও ত্রুটি নেই) সরল 'যদি' বিবৃতি দিয়ে অনিচ্ছাকৃত আচরণকে বাধা দেয়:

#define FOO(x)  f(x); g(x)

if (test) FOO( baz);

এতে প্রসারিত:

if (test) f(baz); g(baz);

যা সিনথেটিকভাবে সঠিক তাই কোনও সংকলক ত্রুটি নেই, তবে সম্ভবত অনিচ্ছাকৃত পরিণাম রয়েছে যা জি () সর্বদা ডাকা হবে।


22
"বোধহয় অনিচ্ছাকৃত"? আমি "অবশ্যই অনিচ্ছাকৃত" বলেছি, অন্যথায় প্রোগ্রামারকে বাইরে নিয়ে গিয়ে গুলি করতে হবে (একটি চাবুকের সাথে গোলমাল শাস্তির বিপরীতে)।
লরেন্স ডল

4
অথবা যদি তারা কোনও তিন-অক্ষরের এজেন্সির জন্য কাজ করে এবং গোপনীয়তার সাথে সেই কোডটি একটি বহুল ব্যবহৃত-ওপেন সোর্স প্রোগ্রামে
tingোকানো

2
এবং এই মন্তব্যটি আমাকে কেবল অ্যাপল ওএসে পাওয়া এসএসএল শংসাপত্র যাচাইয়ের বাগটিতে গেট ব্যর্থ রেখার কথা মনে করিয়ে দেয়
জেরার্ড সেক্সটন

23

উপরের উত্তরগুলি এই নির্মাণগুলির অর্থ ব্যাখ্যা করে তবে দুটিটির মধ্যে উল্লেখযোগ্য পার্থক্য রয়েছে যা উল্লেখ করা হয়নি। আসলে পছন্দ একটি কারণ do ... whileজন্য if ... elseকনস্ট্রাক্ট।

if ... elseকনস্ট্রাক্টের সমস্যাটি হ'ল এটি আপনাকে সেমিকোলন স্থাপন করতে বাধ্য করে না । এই কোডে পছন্দ করুন:

FOO(1)
printf("abc");

যদিও আমরা সেমিকোলনটি ছেড়ে দিয়েছি (ভুল করে), কোডটি প্রসারিত হবে

if (1) { f(X); g(X); } else
printf("abc");

এবং নিঃশব্দে সংকলন করবে (যদিও কিছু সংকলক অ্যাক্সেসযোগ্য কোডের জন্য একটি সতর্কতা জারি করতে পারে)। তবে printfবিবৃতি কখনই কার্যকর করা হবে না।

do ... whileকনস্ট্রাক্টটিতে এ জাতীয় সমস্যা নেই কারণ একমাত্র while(0)সেমিকোলনের পরে বৈধ টোকেন ।


2
@ রিচার্ডহানসেন: এখনও ততটা ভালো নয়, কারণ ম্যাক্রো অনুরোধটি দেখে আপনি জানেন না যে এটি কোনও বিবৃতিতে বা অভিব্যক্তিতে প্রসারিত হয়েছে কিনা। যদি কেউ পরে ধরে নেয় তবে সে লিখতে পারে FOO(1),x++;যা আমাদের আবার একটি মিথ্যা ইতিবাচক দিক দেয়। শুধু ব্যবহার করুন do ... whileএবং এটি।
ইয়াকভ গালকা

1
ভুল বোঝাবুঝি এড়াতে ম্যাক্রোর ডকুমেন্টিংয়ে যথেষ্ট হওয়া উচিত। আমি সম্মত হই যে do ... while (0)এটি পছন্দনীয়, তবে এটির একটি খারাপ দিক রয়েছে: এ breakবা লুপটি continueনিয়ন্ত্রণ করবে do ... while (0), ম্যাক্রো অনুরোধ সম্বলিত লুপটি নয়। সুতরাং ifকৌশল এখনও মান আছে।
রিচার্ড হ্যানসেন

2
আমি দেখতে পাচ্ছি না আপনি কোথায় breakবা এমন একটি continueরাখতে পারেন যা আপনার ম্যাক্রো do {...} while(0)সিউডো-লুপের ভিতরে দেখা যাবে । এমনকি ম্যাক্রো প্যারামিটারে এটি একটি সিনট্যাক্স ত্রুটি করে।
প্যাট্রিক Schlüter

5
নির্মাণের do { ... } while(0)পরিবর্তে ব্যবহারের আরেকটি কারণ if whateverহ'ল এটির মূ .় স্বভাব। do {...} while(0)কনস্ট্রাক্ট ব্যাপক, সুপরিচিত এবং অনেক প্রোগ্রামাররা দ্বারা অনেক ব্যবহার করা হয়। এর যুক্তি এবং ডকুমেন্টেশন সহজেই পরিচিত। ifনির্মাণের জন্য তাই না । কোড পর্যালোচনা করার সময় কুঁচকে যাওয়ার জন্য কম প্রচেষ্টা লাগে।
প্যাট্রিক Schlüter

1
@ ত্রিস্টোপিয়া: আমি লোককে ম্যাক্রো লিখতে দেখেছি যা কোডগুলির ব্লককে আর্গুমেন্ট হিসাবে গ্রহণ করে (যা আমি অবশ্যই সুপারিশ করি না)। উদাহরণস্বরূপ: #define CHECK(call, onerr) if (0 != (call)) { onerr } else (void)0। মনে হচ্ছে ব্যবহার করা যেতে পারে CHECK(system("foo"), break;);, যেখানে break;লুপ পরিক্ষেপ উল্লেখ করতে দেয়ার উদ্দেশ্যে করা হচ্ছে CHECK()আবাহন।
রিচার্ড হ্যানসেন

16

যদিও এটি প্রত্যাশিত যে সংকলকগুলি do { ... } while(false);লুপগুলি অপ্টিমাইজ করে , সেখানে আরও একটি সমাধান রয়েছে যার জন্য সেই নির্মাণ প্রয়োজন হয় না। সমাধানটি কমা অপারেটরটি ব্যবহার করার জন্য:

#define FOO(X) (f(X),g(X))

বা আরও বহিরাগতভাবে:

#define FOO(X) g((f(X),(X)))

যদিও এটি পৃথক নির্দেশাবলীর সাথে ভালভাবে কাজ করবে, এটি ভেরিয়েবলগুলি নির্মিত এবং এর অংশ হিসাবে ব্যবহার করা হয় এমন ক্ষেত্রে কাজ করবে না #define:

#define FOO(X) (int s=5,f((X)+s),g((X)+s))

এটির সাহায্যে নির্মাণের সময় কর / ব্যবহার করতে বাধ্য করা হবে।


ধন্যবাদ, যেহেতু কমা অপারেটর মৃত্যুদণ্ডের আদেশের গ্যারান্টি দেয় না, তাই এই বাসা বাঁধাই এটি প্রয়োগ করার একটি উপায়।
মারিয়াস

15
@ মারিয়াস: মিথ্যা; কমা অপারেটর একটি ক্রম বিন্দু ফলে করেন গ্যারান্টি সঞ্চালনের অর্ডার। আমি সন্দেহ করি আপনি এটি ফাংশন আর্গুমেন্ট তালিকার কমা দিয়ে বিভ্রান্ত করেছেন।
আর .. গীটহাব বন্ধ করুন ICE

2
দ্বিতীয় বিদেশী পরামর্শটি আমার দিনটিকে তৈরি করেছিল।
স্পাইডি

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

@MarcoA। আপনি সঠিক হিসাবে, আমি অতীতে খুঁজে পেয়েছি যে সংকলক অপ্টিমাইজেশন, ঠিক কোডের ফাংশন সংরক্ষণ করার সময়, তবে একক প্রসঙ্গে কিছু না বলে মনে হচ্ছে এমন লাইনগুলি পরিবর্তন করে বহুবিধিত অ্যালগরিদমকে ভেঙে ফেলবে। পয়েন্টে কেস Peterson's Algorithm
মারিয়াস

11

জেনস গুষ্ট্টেটের পি 99 প্রিপ্রোসেসর লাইব্রেরি (হ্যাঁ, এই জাতীয় একটি জিনিসটি আমার মনকেও ফুঁ দিয়েছিল!) if(1) { ... } elseনিম্নরূপটি সংজ্ঞায়িত করে একটি ছোট তবে উল্লেখযোগ্য উপায়ে নির্মাণের ক্ষেত্রে উন্নতি করে :

#define P99_NOP ((void)0)
#define P99_PREFER(...) if (1) { __VA_ARGS__ } else
#define P99_BLOCK(...) P99_PREFER(__VA_ARGS__) P99_NOP

এর পক্ষে যুক্তিটি হ'ল, do { ... } while(0)কনস্ট্রাক্টের বিপরীতে breakএবং continueএখনও প্রদত্ত ব্লকের ভিতরে কাজ ((void)0)করে তবে ম্যাক্রো কল করার পরে যদি সেমিকোলন বাদ দেওয়া হয় তবে একটি বাক্য গঠন ত্রুটি তৈরি করে, যা অন্যথায় পরবর্তী ব্লকটি এড়িয়ে যায় would (এখানে আসলে "ঝুঁকির অন্য কোনও সমস্যা নেই", যেহেতু elseনিকটতমের সাথে বাঁধাই if, যা ম্যাক্রোর মধ্যে একটি)

আপনি যদি সি প্রিপ্রসেসরের সাহায্যে আরও কম-বেশি নিরাপদে করা যায় এমন কিছু বিষয়ে আগ্রহী হন তবে সেই লাইব্রেরিটি দেখুন।


খুব চতুর অবস্থায়, এর ফলে অন্যটি সম্ভাব্য ঝুঁকির বিষয়ে সংকলক সতর্কবার্তা সহ একজনকে বোমা ফাটাচ্ছে।
সিগমেন্টেড

1
আপনি সাধারণত একটি অন্তর্ভুক্ত পরিবেশ তৈরি করতে ম্যাক্রোগুলি ব্যবহার করেন, অর্থাত্ আপনি বাইরে কখনও শুরু / শেষ হওয়া লুপটি নিয়ন্ত্রণ করতে কোনও ম্যাক্রোর অভ্যন্তরে কখনও break(বা continue) ব্যবহার করেন না এটি কেবল খারাপ শৈলী এবং সম্ভাব্য প্রস্থান পয়েন্টগুলি গোপন করে।
মীরাবিলো

বুস্টে একটি প্রিপ্রসেসর লাইব্রেরিও রয়েছে। এটি সম্পর্কে মনের ভাব কি?
রেনে

ঝুঁকিটি else ((void)0)হ'ল যে কেউ হয়ত লিখছেন YOUR_MACRO(), f();এবং এটি সিন্টেক্সিকভাবে বৈধ হবে, তবে কখনও কল করবেন না f()do whileএটির সাথে একটি সিনট্যাক্স ত্রুটি।
মেলপোমেন

@ মেলপোমেন তাহলে কি হবে else do; while (0)?
কার্ল লেই

8

কিছু কারণে আমি প্রথম উত্তরে মন্তব্য করতে পারি না ...

আপনারা কেউ কেউ স্থানীয় ভেরিয়েবল সহ ম্যাক্রোগুলি দেখিয়েছেন, তবে কেউই উল্লেখ করেনি যে আপনি কেবল কোনও ম্যাক্রোতে কোনও নাম ব্যবহার করতে পারবেন না! এটি কোনও দিন ব্যবহারকারীকে কামড় দেবে! কেন? কারণ ইনপুট আর্গুমেন্টগুলি আপনার ম্যাক্রো টেম্পলেটটিতে প্রতিস্থাপিত হয়। এবং আপনার ম্যাক্রোর উদাহরণগুলিতে আপনি সম্ভবত সবচেয়ে বেশি ব্যবহৃত ভেরিয়েবল নাম ব্যবহার করেছেন i

উদাহরণস্বরূপ যখন নিম্নলিখিত ম্যাক্রো

#define FOO(X) do { int i; for (i = 0; i < (X); ++i) do_something(i); } while (0)

নিম্নলিখিত ফাংশনে ব্যবহৃত হয়

void some_func(void) {
    int i;
    for (i = 0; i < 10; ++i)
        FOO(i);
}

ম্যাক্রো इच्छित ভেরিয়েবল i ব্যবহার করবে না, এটি কিছু_ফুনকের শুরুতে ঘোষিত হয়েছে, তবে স্থানীয় ভেরিয়েবল, যা ম্যাক্রোর লুপের সময় ঘোষিত হয় ...

সুতরাং, ম্যাক্রোতে কখনই সাধারণ পরিবর্তনশীল নাম ব্যবহার করবেন না!


সাধারণ প্যাটার্নটি হ'ল ম্যাক্রোগুলিতে পরিবর্তনশীল নামেরগুলিতে আন্ডারস্কোর যুক্ত করা add উদাহরণস্বরূপ int __i;
ব্লেজারব্লেড

8
@ ব্লাইজারব্লেড: আসলে এটি ভুল এবং অবৈধ সি; নেতৃস্থানীয় আন্ডারস্কোরগুলি প্রয়োগ দ্বারা ব্যবহারের জন্য সংরক্ষিত। আপনি এই "স্বাভাবিক প্যাটার্ন "টি দেখেছেন কারণ হ'ল সিস্টেম শিরোনামগুলি (" বাস্তবায়ন ") যা নিজেকে এই সংরক্ষিত নাম স্থানে সীমাবদ্ধ রাখতে হবে from অ্যাপ্লিকেশন / গ্রন্থাগারগুলির জন্য আপনার নিজের অস্পষ্ট, আন্ডারস্কোর ছাড়াই সম্ভাব্য-সংঘর্ষের নামগুলি বেছে নেওয়া উচিত, যেমন mylib_internal___iবা অনুরূপ similar
আর .. গীটহাব বন্ধ করুন ICE

2
@ আর .. আপনি ঠিক বলেছেন - লিনাক্স কার্নেলটি আমি একটি '' অ্যাপ্লিকেশন '' এ পড়েছি তবে এটি ব্যতিক্রম যেহেতু এটি কোনও স্ট্যান্ডার্ড লাইব্রেরি ব্যবহার করে না (প্রযুক্তিগতভাবে, একটি '' ফ্রিস্ট্যান্ডিং '' সি প্রয়োগকরণ) একটি '' হোস্টেড '' এক)।
ব্লেসরব্ল্যাড

3
@ আর .. এটি একেবারেই সঠিক নয়: মূলধন বা দ্বিতীয় আন্ডারস্কোর অনুসরণকারী শীর্ষস্থানীয় আন্ডারস্কোরগুলি সমস্ত প্রসঙ্গে প্রয়োগের জন্য সংরক্ষিত। নেতৃস্থানীয় আন্ডারস্কোরগুলি অনুসরণ করে স্থানীয় কিছু ক্ষেত্রে সংরক্ষিত নেই।
লিউশেনকো

@ লুশেনকো: হ্যাঁ, তবে পার্থক্যটি যথেষ্ট সূক্ষ্ম যে আমি লোকদের কেবল এই জাতীয় নাম ব্যবহার না করাই বলাই ভাল। যে সূক্ষ্মতা সম্ভবত লোকেরা বুঝতে পারে তারা ইতিমধ্যে জানে যে আমি বিশদগুলি নিয়ে চকচকে করছি। :-)
আর .. গিটহাব বন্ধ করুন ICE

6

ব্যাখ্যা

do {} while (0)এবং if (1) {} elseম্যাক্রোটি কেবলমাত্র 1 নির্দেশিকায় প্রসারিত হয়েছে তা নিশ্চিত করা উচিত। অন্যথায়:

if (something)
  FOO(X); 

এতে প্রসারিত হবে:

if (something)
  f(X); g(X); 

এবং নিয়ন্ত্রণ বিবৃতি g(X)বাইরে কার্যকর করা হবে if। এটি ব্যবহার করার সময় do {} while (0)এবং এড়ানো যায় if (1) {} else


আরও ভাল বিকল্প

একটি গনুহ সঙ্গে বিবৃতি প্রকাশের (না প্রমিত C এর একটি অংশ), আপনি চেয়ে ভাল উপায় আছে do {} while (0)এবং if (1) {} elseএই সমস্যার সমাধানের, সহজভাবে ব্যবহার করে ({}):

#define FOO(X) ({f(X); g(X);})

এবং এই বাক্য গঠনটি রিটার্ন মানগুলির সাথে সামঞ্জস্যপূর্ণ (নোটটি এটি do {} while (0)নয়), যেমন:

return FOO("X");

3
ম্যাক্রোতে ব্লক-ক্ল্যাম্পিং} use এর ব্যবহার ম্যাক্রো কোড বান্ডিল করার জন্য যথেষ্ট হবে যাতে সমস্ত একই অবস্থা-শর্তের পথের জন্য কার্যকর করা হয়। ম্যাক্রো যে জায়গাগুলিতে ব্যবহৃত হয় সে জায়গাগুলিতে সেমিকোলন প্রয়োগের জন্য ডু-ওয়াইডটি প্রায় ব্যবহৃত হয়। এইভাবে ম্যাক্রো আরও কার্যকরভাবে একইভাবে আচরণ করার জন্য প্রয়োগ করা হয়। এর মধ্যে যখন ব্যবহার করা হয় তখন পেছনের অর্ধেকোলনের প্রয়োজনীয়তা অন্তর্ভুক্ত।
আলেকজান্ডার স্টোহর

2

আমি মনে করি না যে এটি উল্লেখ করা হয়েছিল তাই এটি বিবেচনা করুন

while(i<100)
  FOO(i++);

অনুবাদ করা হবে

while(i<100)
  do { f(i++); g(i++); } while (0)

i++ম্যাক্রো দ্বারা কীভাবে দুবার মূল্যায়ন করা হয় তা লক্ষ্য করুন । এটি কিছু আকর্ষণীয় ত্রুটি হতে পারে।


15
এটির (0) নির্মাণের সাথে কিছুই করার নেই।
ট্রেন্ট

2
সত্য। তবে ম্যাক্রো বনাম ফাংশন এবং কীভাবে কোনও ম্যাক্রো যা একটি ফাংশন হিসাবে আচরণ করে তা কীভাবে লিখতে হয় সে বিষয়ে প্রচ্ছন্ন ...
জন নিলসন

2
অনুরূপভাবে উপরেরটির মতো, এটি কোনও উত্তর নয় তবে একটি মন্তব্য। do { int macroname_i = (i); f(macroname_i); g(macroname_i); } while (/* CONSTCOND */ 0)
বিষয়টিতে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.