কীভাবে একটি ভেরিয়েডিক ম্যাক্রো করবেন (আর্গুমেন্টের পরিবর্তনশীল সংখ্যা)


196

আমি সি তে একটি ম্যাক্রো লিখতে চাই যা নির্দিষ্ট সংখ্যা নয়, কোনও পরামিতি গ্রহণ করে

উদাহরণ:

#define macro( X )  something_complicated( whatever( X ) )

যেখানে Xপ্যারামিটারের সংখ্যা রয়েছে

আমার এটি দরকার কারণ whateverঅতিরিক্ত লোড হয়েছে এবং 2 বা 4 পরামিতিগুলির সাথে কল করা যেতে পারে।

আমি দুবার ম্যাক্রো সংজ্ঞায়িত করার চেষ্টা করেছি, তবে দ্বিতীয় সংজ্ঞাটি প্রথমটির ওভাররোট করে!

আমি যে সংকলকটির সাথে কাজ করছি তা হ'ল জি ++ (আরও নির্দিষ্টভাবে বলা যায়, মিংডাব্লু)


8
আপনি সি বা সি ++ চান? আপনি যদি সি ব্যবহার করছেন, আপনি কেন একটি সি ++ সংকলক দিয়ে সংকলন করছেন? যথাযথ সি 99 ভেরিয়্যাডিক ম্যাক্রোগুলি ব্যবহার করার জন্য, আপনার সি-কম্পাইলারটি সংকলন করা উচিত যা সি 99 সমর্থন করে (জিসিসি এর মতো), কোন সি ++ সংকলক নয়, যেহেতু সি ++ তে স্ট্যান্ডার্ড ভেরিয়েডিক ম্যাক্রোগুলি নেই।
ক্রিস লুৎজ

ঠিক আছে, আমি ধরে নিয়েছি যে সি ++ এই ক্ষেত্রে সি এর একটি সুপার সেট ..
হ্যাসেন

tigcc.icalc.org/doc/cpp.html#SEC13 এর ভ্যারিয়্যাডিক ম্যাক্রোগুলির বিশদ ব্যাখ্যা রয়েছে।
Gnubie

একটি ভাল ব্যাখ্যা এবং উদাহরণ এখানে http://gcc.gnu.org/onlinesocs/cpp/Variadic-Macros.html
জাফরুলক

3
ভবিষ্যতের পাঠকদের জন্য: সি সি ++ এর সাবস্টেটি নয় । তারা অনেকগুলি জিনিস ভাগ করে, কিন্তু এমন কিছু বিধি রয়েছে যা তাদের একে অপরের উপসেট এবং সুপারসেট হওয়া বন্ধ করে দেয়।
ফারাপ

উত্তর:


295

সি 99 উপায়, ভিসি ++ সংকলক দ্বারা সমর্থিত।

#define FOO(fmt, ...) printf(fmt, ##__VA_ARGS__)

8
আমি ভাবি না যে VA_ARGS এর আগে C99 এর জন্য ## প্রয়োজন । এটি কেবল ভিসি ++ হতে পারে।
ক্রিস লুৎজ

97
ভিএআরজিএসের আগে ## এর কারণ হ'ল ভেরিয়েবল-আর্গুমেন্টের তালিকা খালি থাকার ক্ষেত্রে এটি পূর্ববর্তী কমাটি গ্রাস করে। FOO ("a") প্রিন্টফ ("a") এ প্রসারিত হয়েছে। এটি জিসিসি (এবং ভিসি ++, সম্ভবত) এর একটি এক্সটেনশান, C99 এর জন্য এলিসিসের জায়গায় উপস্থিত হওয়ার জন্য কমপক্ষে একটি যুক্তি প্রয়োজন।
jpalecek

108
##প্রয়োজন হয় না এবং পোর্টেবল হয় না। #define FOO(...) printf(__VA_ARGS__)কাজ বহনযোগ্য উপায় করে; fmtপরামিতি সংজ্ঞা থেকে বাদ দেওয়া যেতে পারে।
আলেকোভ

4
আইআইআরসি, ## এটি জিসিসি নির্দিষ্ট এবং এটি শূন্য প্যারামিটারগুলি পাস করার অনুমতি দেয়
মাওগ বলেছেন

10
## - সিনট্যাক্স llvm / কলং এবং ভিজ্যুয়াল স্টুডিও সংকলকটিতেও কাজ করে। সুতরাং এটি পোর্টেবল নাও হতে পারে তবে এটি প্রধান সংকলকগুলি দ্বারা সমর্থিত।
কে। বীরমান

37

__VA_ARGS__এটি করার মানক উপায়। আপনার যদি না করতে হয় তবে সংকলক-নির্দিষ্ট হ্যাকগুলি ব্যবহার করবেন না।

আমি সত্যিই বিরক্ত যে আমি মূল পোস্টে মন্তব্য করতে পারি না। যাই হোক না কেন, সি ++ সি এর সুপারসেট নয় এটি আপনার সি কোডকে একটি সি ++ কম্পাইলার দিয়ে সংকলন করা সত্যিই বোকামি। ডোনি যা করেন না তা করবেন না।


8
"আপনার সি কোডটি একটি সি ++ সংকলক দিয়ে সংকলন করা সত্যিই নির্বোধ" => প্রত্যেকের দ্বারা এটি বিবেচনা করা হয়নি (আমাকে সহ)। উদাহরণস্বরূপ সি ++ মূল নির্দেশিকাগুলি দেখুন: সিপিএল 1: সি ++ কে সি , সিপিএল 2 পছন্দ করুন: আপনার যদি সি ব্যবহার করতে হয় তবে সি এবং সি ++ এর সাধারণ উপসেটটি ব্যবহার করুন এবং সি কোডটি সি ++ হিসাবে সংকলন করুন । সামঞ্জস্যপূর্ণ সাবসেটে প্রোগ্রামিং না করার জন্য কোনটি "সি-ওয়ানডেম-ইসমস" এর সত্যিকার অর্থে কী দরকার তা ভেবে আমি কঠোর চাপে পড়েছি এবং সি এবং সি ++ কমিটি সেই সামঞ্জস্যপূর্ণ সাবসেটটি উপলব্ধ করার জন্য কঠোর পরিশ্রম করেছে।
হোস্টাইলফোর্ক বলেছেন যে এসই

4
@ হোস্টাইলফর্ক মেলা যথেষ্ট, যদিও অবশ্যই সি ++ জনগণ সি ++ ব্যবহারকে উত্সাহিত করতে চাইবেন। অন্যরা যদিও একমত না; লিনাক্স টোরভাল্ডস, উদাহরণস্বরূপ, দৃশ্যত প্রত্যাখ্যান করেছেন একাধিক লিনাক্স কার্নেল প্যাচ যে আইডেন্টিফায়ার প্রতিস্থাপন করার প্রচেষ্টা প্রস্তাবিত classসঙ্গে klassএকটি সি ++ কম্পাইলার দিয়ে কম্পাইল করার অনুমতি। এছাড়াও লক্ষ করুন যে কিছু পার্থক্য রয়েছে যা আপনাকে ট্রিপ করবে; উদাহরণস্বরূপ, তিন ভাষা অপারেটর উভয় ভাষায় একইভাবে মূল্যায়ন করা হয় না, এবং inlineকীওয়ার্ডটির অর্থ সম্পূর্ণ ভিন্ন কিছু (যেমন আমি একটি ভিন্ন প্রশ্ন থেকে শিখেছি)।
কাইল স্ট্র্যান্ড

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

2
@ ডাউনবিট আপনি উত্পাদনের জন্য সি ++ ব্যবহার করুন বা না করুন, যদি এটি আপনার সম্পর্কে উদ্বিগ্ন হয় তবে আপনি সি ++ এর সাথে সংকলন করতে সক্ষম হওয়া স্থির বিশ্লেষণের জন্য যাদু করার ক্ষমতা দেয়। আপনার যদি একটি কোয়েরি থাকে তবে আপনি একটি সি কোডবাস তৈরি করতে চান ... কিছু ধরণের নির্দিষ্ট উপায়ে ব্যবহার করা হচ্ছে কিনা তা নিয়ে ভাবছেন, টাইপ_ট্রেটগুলি কীভাবে ব্যবহার করবেন তা শিখতে এর জন্য লক্ষ্যবস্তু সরঞ্জাম তৈরি করতে পারে। আপনি সি এর স্ট্যাটিক বিশ্লেষণ সরঞ্জামের জন্য বড় অঙ্কের অর্থ যা দিয়েছিলেন তা কিছুটা সি ++ দিয়ে করা যেতে পারে আপনার কীভাবে এবং
সংকলকটি

1
আমি লিনাক্স প্রশ্নে কথা বলছি। (আমি শুধু লক্ষ্য করেছি যে, এটা বলে "লিনাক্স টোরভাল্ডস" হা!)
নৈরাশ্যবাদী

28

আমি মনে করি না এটি সম্ভব, আপনি ডাবল পেরেন দিয়ে এটি জাল করতে পারবেন ... যতক্ষণ না আপনার স্বতন্ত্রভাবে যুক্তিগুলির প্রয়োজন হয় না।

#define macro(ARGS) some_complicated (whatever ARGS)
// ...
macro((a,b,c))
macro((d,e))

21
বৈকল্পিক ম্যাক্রো পাওয়া সম্ভব হলেও, ডাবল প্রথম বন্ধনী ব্যবহার করা ভাল পরামর্শ।
ডেভিড রদ্রিগেজ - ড্রিবাস

2
মাইক্রোচিপের XC সংকলক ভ্যারায়ডিক ম্যাক্রোগুলি সমর্থন করে না এবং তাই এই ডাবল প্রথম বন্ধনী কৌশলটি আপনি করতে পারেন সেরা।
gbmhunter

10
#define DEBUG

#ifdef DEBUG
  #define PRINT print
#else
  #define PRINT(...) ((void)0) //strip out PRINT instructions from code
#endif 

void print(const char *fmt, ...) {

    va_list args;
    va_start(args, fmt);
    vsprintf(str, fmt, args);
        va_end(args);

        printf("%s\n", str);

}

int main() {
   PRINT("[%s %d, %d] Hello World", "March", 26, 2009);
   return 0;
}

সংকলকটি যদি ভ্যারিয়েডিক ম্যাক্রোগুলি বুঝতে না পারে তবে আপনি নীচের যে কোনওটির সাথেও PRINT কেটে ফেলতে পারেন:

#define PRINT //

অথবা

#define PRINT if(0)print

প্রথম প্রিন্ট নির্দেশাবলী সম্পর্কে মন্তব্য, দ্বিতীয় শর্ত যদি একটি NULL কারণে PRINT নির্দেশনা প্রতিরোধ করে। অপ্টিমাইজেশন সেট করা থাকলে, সংকলকটি কখনই সম্পাদিত নির্দেশাবলীর বাইরে ফেলা উচিত নয়: যদি (0) মুদ্রণ ("হ্যালো ওয়ার্ল্ড"); বা (শূন্য) 0);



8
# 0 নির্দিষ্ট প্রিন্ট যদি (0) মুদ্রণটি ভাল ধারণা না হয় কারণ কলিং কোডটির নিজস্ব নিজস্ব অন্য কোনও থাকতে পারে - PRINT কল করার জন্য যদি। আরও ভাল: #
নির্ধারিত

3
মানক "কিছুই করবেন না, করুণাময়" করছেন {} যখন (0)
ভোনব্র্যান্ড

ifকোড স্ট্রাকচারকে বিবেচনা করে এমন "এটি করবেন না" এর যথাযথ সংস্করণটি হ'ল: if (0) { your_code } elseআপনার ম্যাক্রো সম্প্রসারণটি সমাপ্ত করে একটি আধা-কোলন elsewhileসংস্করণ দেখে মনে হচ্ছে: while(0) { your_code } সমস্যাটির do..whileসংস্করণ যে কোড রয়েছে do { your_code } while (0)একবার সম্পন্ন হলে, নিশ্চিত। তিনটি ক্ষেত্রেই যদি your_codeখালি থাকে তবে এটি যথাযথ do nothing gracefully
জেসি চিশল্ম

4

জি ++ এর জন্য এখানে ব্যাখ্যা করা হয়েছে, যদিও এটি C99 এর অংশ তাই সবার জন্য কাজ করা উচিত

http://www.delorie.com/gnu/docs/gcc/gcc_44.html

দ্রুত উদাহরণ:

#define debug(format, args...) fprintf (stderr, format, args)

3
জিসিসির ভেরিয়্যাডিক ম্যাক্রোগুলি সি 99 ভেরিয়েডিক ম্যাক্রো নয়। জিসিসি হয়েছে C99 variadic ম্যাক্রো কিন্তু জি ++, তাদের সমর্থন করে না, কারণ C99 C ++ অংশ নয়।
ক্রিস লুৎজ

1
আসলে জি ++ সি ++ ফাইলগুলিতে সি 99 ম্যাক্রোগুলি সংকলন করবে। এটি 'বিস্ময়কর' দিয়ে সংকলিত হলেও এটি একটি সতর্কতা জারি করবে।
অ্যালেক্স বি

2
এটি C99 নয়। C99 VA_ARGS ম্যাক্রো ব্যবহার করুন )।
qrdl

1
সি ++ 11 এছাড়াও সমর্থন করে __VA_ARGS__, যদিও এটি পূর্ববর্তী সংস্করণগুলির সংযোজনকারীরা পাশাপাশি এক্সটেনশন হিসাবে সমর্থন করে।
ইথুরিস

1
এটি প্রিন্টফের জন্য কাজ করতে ব্যর্থ ("হাই"); যেখানে কোনও ভেরি আরগ নেই। এটি ঠিক করার কোনও জেনেরিক উপায়?
বিটিআর নাইডু
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.