আমি সর্বদা উদাহরণ এবং ক্ষেত্রে দেখেছি যেখানে ম্যাক্রো ব্যবহার করা ফাংশন ব্যবহারের চেয়ে ভাল।
কোনও ফাংশনের তুলনায় ম্যাক্রোর অসুবিধে কেউ আমাকে উদাহরণ দিয়ে ব্যাখ্যা করতে পারেন?
আমি সর্বদা উদাহরণ এবং ক্ষেত্রে দেখেছি যেখানে ম্যাক্রো ব্যবহার করা ফাংশন ব্যবহারের চেয়ে ভাল।
কোনও ফাংশনের তুলনায় ম্যাক্রোর অসুবিধে কেউ আমাকে উদাহরণ দিয়ে ব্যাখ্যা করতে পারেন?
উত্তর:
ম্যাক্রোগুলি ত্রুটি-প্রবণ কারণ তারা পাঠ্য প্রতিস্থাপনার উপর নির্ভর করে এবং প্রকার-চেকিং করে না। উদাহরণস্বরূপ, এই ম্যাক্রো:
#define square(a) a * a
একটি পূর্ণসংখ্যার সাথে ব্যবহৃত হলে সূক্ষ্মভাবে কাজ করে:
square(5) --> 5 * 5 --> 25
তবে খুব অদ্ভুত কাজগুলি যখন প্রকাশের সাথে ব্যবহৃত হয়:
square(1 + 2) --> 1 + 2 * 1 + 2 --> 1 + 2 + 2 --> 5
square(x++) --> x++ * x++ --> increments x twice
যুক্তিগুলির চারপাশে প্রথম বন্ধন রাখার সাহায্য করে তবে এই সমস্যাগুলি সম্পূর্ণরূপে মুছে ফেলা হয় না।
যখন ম্যাক্রোতে একাধিক বিবৃতি থাকে, আপনি নিয়ন্ত্রণ-প্রবাহের নির্মাণগুলি নিয়ে সমস্যায় পড়তে পারেন:
#define swap(x, y) t = x; x = y; y = t;
if (x < y) swap(x, y); -->
if (x < y) t = x; x = y; y = t; --> if (x < y) { t = x; } x = y; y = t;
এটি ঠিক করার জন্য সাধারণ কৌশলটি হ'ল "ডু {...} করার সময় (0)" লুপের মধ্যে বিবৃতি রাখা।
যদি আপনার কাছে দুটি কাঠামো থাকে যা একই নামের সাথে পৃথক শব্দার্থবিজ্ঞানের ক্ষেত্র ধারণ করে তবে একই ম্যাক্রো অদ্ভুত ফলাফল সহ উভয়কেই কার্যকর করতে পারে:
struct shirt
{
int numButtons;
};
struct webpage
{
int numButtons;
};
#define num_button_holes(shirt) ((shirt).numButtons * 4)
struct webpage page;
page.numButtons = 2;
num_button_holes(page) -> 8
অবশেষে, ম্যাক্রোগুলি ডিবাগ করা কঠিন হতে পারে, অদ্ভুত সিনট্যাক্স ত্রুটি বা রানটাইম ত্রুটিগুলি যা আপনাকে বুঝতে বাড়াতে হবে (উদাহরণস্বরূপ gcc -E সহ) তৈরি করতে পারে, কারণ ডিবাগারগুলি ম্যাক্রোগুলির মাধ্যমে পদক্ষেপ নিতে পারে না, উদাহরণস্বরূপ:
#define print(x, y) printf(x y) /* accidentally forgot comma */
print("foo %s", "bar") /* prints "foo %sbar" */
ইনলাইন ফাংশন এবং ধ্রুবকগুলি ম্যাক্রোগুলির সাথে এই সমস্যাগুলির অনেকগুলি এড়াতে সহায়তা করে তবে সর্বদা প্রযোজ্য নয়। যেখানে ম্যাক্রোজগুলি ইচ্ছাকৃতভাবে পলিমারফিক আচরণ নির্দিষ্ট করতে ব্যবহৃত হয়, সেখানে অনিচ্ছাকৃত বহুবচন এড়ানো কঠিন হতে পারে। সি ++ এর অনেকগুলি বৈশিষ্ট্য রয়েছে যেমন ম্যাক্রো ব্যবহার না করে টাইপসেজাল পদ্ধতিতে জটিল পলিমারফিক কন্সট্রাক্টস তৈরিতে সহায়তা করার জন্য টেমপ্লেটগুলি; বিশদ জানতে স্ট্রাস্ট্রপের সি ++ প্রোগ্রামিং ভাষা দেখুন।
x++*x++
বৃদ্ধি হিসাবে বলা যায় না x
; এটি প্রকৃতপক্ষে অপরিবর্তিত আচরণের জন্য আহ্বান করে , যার অর্থ সংকলকটি যে কোনও কিছু করতে পারে নিখরচায় — এটি x
দ্বিগুণ বা একবার বৃদ্ধি পেতে পারে বা আদৌ নয়; এটি কোনও ত্রুটির সাথে বাতিল করতে পারে বা এমনকি আপনার নাক থেকে অসুরদেরও উড়ে যেতে পারে ।
ম্যাক্রো বৈশিষ্ট্যগুলি :
ফাংশন বৈশিষ্ট্য :
পার্শ্ব প্রতিক্রিয়া একটি বড় এক। এখানে একটি সাধারণ কেস রয়েছে:
#define min(a, b) (a < b ? a : b)
min(x++, y)
এতে প্রসারিত হয়:
(x++ < y ? x++ : y)
x
একই বিবৃতিতে দুবার বর্ধিত হয়। (এবং অপরিবর্তিত আচরণ)
মাল্টি-লাইন ম্যাক্রোগুলি লেখাও ব্যথা:
#define foo(a,b,c) \
a += 10; \
b += 10; \
c += 10;
\
প্রতিটি লাইনের শেষে তাদের প্রয়োজন require
আপনি যদি এটিকে একটি একক অভিব্যক্তি না করেন তবে ম্যাক্রোস "ফিরিয়ে" দিতে পারে না:
int foo(int *a, int *b){
side_effect0();
side_effect1();
return a[0] + b[0];
}
আপনি জিসিসির প্রকাশের বিবৃতি ব্যবহার না করা পর্যন্ত ম্যাক্রোতে এটি করতে পারবেন না। (সম্পাদনা: আপনি কমা অপারেটরটি ব্যবহার করতে পারেন যদিও ... এটি উপেক্ষা করেছেন ... তবে এটি এখনও কম পাঠযোগ্য হতে পারে))
পরিচালনার ক্রম: (@ouah এর সৌজন্যে)
#define min(a,b) (a < b ? a : b)
min(x & 0xFF, 42)
এতে প্রসারিত হয়:
(x & 0xFF < 42 ? x & 0xFF : 42)
তবে &
এর চেয়ে কম নজির রয়েছে <
। তাই 0xFF < 42
প্রথমে মূল্যায়ন হয়।
min(a & 0xFF, 42)
#define SQUARE(x) ((x)*(x))
int main() {
int x = 2;
int y = SQUARE(x++); // Undefined behavior even though it doesn't look
// like it here
return 0;
}
যদিও:
int square(int x) {
return x * x;
}
int main() {
int x = 2;
int y = square(x++); // fine
return 0;
}
struct foo {
int bar;
};
#define GET_BAR(f) ((f)->bar)
int main() {
struct foo f;
int a = GET_BAR(&f); // fine
int b = GET_BAR(&a); // error, but the message won't make much sense unless you
// know what the macro does
return 0;
}
তুলনা করা:
struct foo {
int bar;
};
int get_bar(struct foo *f) {
return f->bar;
}
int main() {
struct foo f;
int a = get_bar(&f); // fine
int b = get_bar(&a); // error, but compiler complains about passing int* where
// struct foo* should be given
return 0;
}
সন্দেহ হলে, ফাংশন (বা ইনলাইন ফাংশন) ব্যবহার করুন।
তবে এখানে উত্তরগুলি বেশিরভাগই ম্যাক্রোগুলির সাথে সমস্যাগুলি ব্যাখ্যা করে, ম্যাক্রোগুলি মন্দ বলে কিছু সাধারণ দৃষ্টিভঙ্গির পরিবর্তে মূ accidents় দুর্ঘটনা সম্ভব।
সমস্যাগুলি সম্পর্কে আপনি সচেতন হতে পারেন এবং সেগুলি এড়াতে শিখতে পারেন। তারপরে ম্যাক্রোগুলি কেবল তখনই ব্যবহার করুন যখন কোনও ভাল কারণ আছে।
কিছু ব্যতিক্রমী মামলা রয়েছে যেখানে ম্যাক্রোগুলি ব্যবহারের সুবিধা রয়েছে, এর মধ্যে রয়েছে:
va_args
। __FILE__
, __LINE__
, __func__
)। প্রাক / পোস্টের শর্তগুলির জন্য পরীক্ষা করুন,assert
ব্যর্থতা বা এমনকি স্থির-জরুরী হিসাবে পরীক্ষা করুন যাতে কোডটি অনুচিত ব্যবহারের জন্য সংকলন না করে (বেশিরভাগ ডিবাগ বিল্ডগুলির জন্য দরকারী)।struct
কাস্টিংয়ের আগে চেক সদস্য উপস্থিত আছেন func(FOO, "FOO");
, আপনি কোনও ম্যাক্রো সংজ্ঞায়িত করতে পারেন যা আপনার জন্য স্ট্রিং প্রসারিত করেfunc_wrapper(FOO);
inline
ফাংশনগুলি একটি বিকল্প হতে পারে) ।স্বীকার্যভাবে, এর মধ্যে কয়েকটি সংকলক এক্সটেনশনের উপর নির্ভর করে যা মান সি না হয় অর্থাত্ আপনি কম পোর্টেবল কোড দিয়ে শেষ করতে পারেন বা এগুলিতে থাকতে পারেন ifdef
, তাই সংকলক যখন সমর্থন করে তখন সেগুলি কেবল তারাই গ্রহণ করা হবে।
এটি ম্যাক্রোগুলিতে ত্রুটির অন্যতম সাধারণ কারণ হিসাবে উদাহরণস্বরূপ লক্ষ করা ( x++
উদাহরণস্বরূপ, যেখানে ম্যাক্রো একাধিকবার বৃদ্ধি করতে পারে) ।
যুক্তিগুলির একাধিক তাত্ক্ষণিকের সাথে পার্শ্ব-প্রতিক্রিয়া এড়ানো ম্যাক্রোগুলি লেখা এটি সম্ভব।
আপনি যদি square
ম্যাক্রো রাখতে চান যা বিভিন্ন ধরণের সাথে কাজ করে এবং সি 11 সমর্থন করে, আপনি এটি করতে পারেন ...
inline float _square_fl(float a) { return a * a; }
inline double _square_dbl(float a) { return a * a; }
inline int _square_i(int a) { return a * a; }
inline unsigned int _square_ui(unsigned int a) { return a * a; }
inline short _square_s(short a) { return a * a; }
inline unsigned short _square_us(unsigned short a) { return a * a; }
/* ... long, char ... etc */
#define square(a) \
_Generic((a), \
float: _square_fl(a), \
double: _square_dbl(a), \
int: _square_i(a), \
unsigned int: _square_ui(a), \
short: _square_s(a), \
unsigned short: _square_us(a))
এটি জিসিসি, ক্ল্যাং, ইকোপাথ এবং ইন্টেল সি ++ (তবে এমএসভিসি নয়) দ্বারা সমর্থিত একটি সংকলক এক্সটেনশন ;
#define square(a_) __extension__ ({ \
typeof(a_) a = (a_); \
(a * a); })
সুতরাং ম্যাক্রোগুলির অসুবিধাগুলি হ'ল এগুলি শুরু করার জন্য আপনার ব্যবহার করা জেনে রাখা উচিত এবং এগুলি ব্যাপকভাবে সমর্থিত নয়।
একটি সুবিধা হ'ল এই ক্ষেত্রে, আপনি একই square
ফাংশনটি বিভিন্ন ধরণের জন্য ব্যবহার করতে পারেন ।
প্যারামিটার এবং কোডের কোনও ধরণের চেকিং পুনরাবৃত্তি করা হয় যা কোড ফোলা বাড়ে। ম্যাক্রো সিনট্যাক্সের ফলে অনেকগুলি অদ্ভুত প্রান্তের ঘটনাও ঘটতে পারে যেখানে আধা-কলোন বা অগ্রাধিকারের অর্ডার আসতে পারে। এখানে একটি লিঙ্ক যা কিছু ম্যাক্রো অশুভতা প্রদর্শন করে
ম্যাক্রোগুলির একটি অপূর্ণতা হ'ল ডিবাগারগুলি সোর্স কোডটি পড়েন, যার ম্যাক্রোগুলি প্রসারিত হয় না, সুতরাং ম্যাক্রোতে একটি ডিবাগার চালানো প্রয়োজনীয় দরকারী নয়। বলা বাহুল্য, আপনি কোনও ম্যাক্রোর ভিতরে কোনও কার্যকারিতা সহ কোনও ব্রেকপয়েন্টটি সেট করতে পারবেন না।
ফাংশনগুলি টাইপ চেকিং করে। এটি আপনাকে সুরক্ষার অতিরিক্ত স্তর দেয়।
এই উত্তরে যুক্ত করা হচ্ছে ..
ম্যাক্রোগুলি প্রিপ্রোসেসর দ্বারা সরাসরি প্রোগ্রামে প্রতিস্থাপিত হয় (যেহেতু তারা মূলত প্রিপ্রোসেসর নির্দেশিকা)। সুতরাং তারা অনিবার্যভাবে একটি সম্পর্কিত ফাংশন চেয়ে বেশি মেমরি স্পেস ব্যবহার। অন্যদিকে, কোনও ফাংশনটির জন্য ডাকা এবং ফলাফলগুলি ফিরে পেতে আরও বেশি সময় প্রয়োজন এবং ম্যাক্রো ব্যবহার করে এই ওভারহেড এড়ানো যেতে পারে।
এছাড়াও বিভিন্ন প্ল্যাটফর্মগুলিতে প্রোগ্রাম বহনযোগ্যতার জন্য ম্যাক্রোগুলির কাছে কিছু বিশেষ সরঞ্জাম রয়েছে।
ফাংশনের বিপরীতে ম্যাক্রোগুলিকে তাদের যুক্তিগুলির জন্য কোনও ডেটা টাইপ দেওয়ার দরকার নেই।
সামগ্রিকভাবে তারা প্রোগ্রামিংয়ে একটি দরকারী সরঞ্জাম। এবং উভয় ম্যাক্রোইনস্ট্রাকশন এবং ফাংশন পরিস্থিতিগুলির উপর নির্ভর করে ব্যবহার করা যেতে পারে।
আমি উপরের উত্তরগুলিতে লক্ষ্য করিনি, ম্যাক্রোগুলির উপরে ফাংশনগুলির একটি সুবিধা যা আমি মনে করি এটি অত্যন্ত গুরুত্বপূর্ণ:
ফাংশনগুলি আর্গুমেন্ট হিসাবে পাস করা যেতে পারে, ম্যাক্রোগুলি পারে না।
কংক্রিট উদাহরণ: আপনি স্ট্যান্ডার্ড 'strpbrk' ফাংশনের একটি বিকল্প সংস্করণ লিখতে চান যা অন্য স্ট্রিংয়ের মধ্যে অনুসন্ধানের জন্য অক্ষরের একটি সুস্পষ্ট তালিকার পরিবর্তে, (একটি পয়েন্টার) ফাংশন যা অক্ষর না হওয়া পর্যন্ত 0 ফিরে আসবে পাওয়া গেছে যে কিছু পরীক্ষা পাস করে (ব্যবহারকারী সংজ্ঞায়িত)। আপনি এটি করতে চাইলে একটি কারণ আপনি অন্যান্য স্ট্যান্ডার্ড লাইব্রেরি ফাংশনগুলি কাজে লাগাতে পারেন: যতিচিহ্নে পূর্ণ স্পষ্ট স্ট্রিং সরবরাহ না করে আপনি ctype.h এর 'ispunct' বদলে পাস করতে পারেন, যদি 'ispunct' কেবল হিসাবে প্রয়োগ করা হত একটি ম্যাক্রো, এটি কাজ করবে না।
অন্যান্য প্রচুর উদাহরণ রয়েছে। উদাহরণস্বরূপ, যদি আপনার তুলনা ফাংশন না করে ম্যাক্রো দ্বারা সম্পন্ন হয় তবে আপনি এটিকে stdlib.h- এর 'qsort' এ দিতে পারবেন না।
পাইথনের অ্যানালগীয় পরিস্থিতি হ'ল সংস্করণ 2 বনাম সংস্করণ 3 (প্রেরণযোগ্য ফাংশন বনাম পাসযোগ্য ফাংশন) এর 'মুদ্রণ'।
আপনি যদি ম্যাক্রোর আর্গুমেন্ট হিসাবে ফাংশনটি পাস করেন তবে এটি প্রতিবার মূল্যায়ন করা হবে। উদাহরণস্বরূপ, আপনি যদি সর্বাধিক জনপ্রিয় কোনও ম্যাক্রো কল করেন:
#define MIN(a,b) ((a)<(b) ? (a) : (b))
সে রকমই
int min = MIN(functionThatTakeLongTime(1),functionThatTakeLongTime(2));
ফাংশনটিটেকলংটাইম 5 বার মূল্যায়ন করা হবে যা পারফরম্যান্স উল্লেখযোগ্যভাবে হ্রাস করতে পারে