কীভাবে সি প্রিপ্রোসেসর দিয়ে দু'বার কনটেনেট করতে হবে এবং "আর্গ ## _ ## ম্যাক্রো" হিসাবে ম্যাক্রো প্রসারিত করবেন?


152

আমি এমন একটি প্রোগ্রাম লেখার চেষ্টা করছি যেখানে কিছু ফাংশনগুলির নাম এই জাতীয় ম্যাক্রোর সাথে নির্দিষ্ট ম্যাক্রো ভেরিয়েবলের মানের উপর নির্ভরশীল:

#define VARIABLE 3
#define NAME(fun) fun ## _ ## VARIABLE

int NAME(some_function)(int a);

দুর্ভাগ্যক্রমে, ম্যাক্রো এটিতে NAME()পরিণত হয়

int some_function_VARIABLE(int a);

বরং

int some_function_3(int a);

সুতরাং এটি পরিষ্কারভাবে এটি সম্পর্কে যেতে ভুল উপায়। ভাগ্যক্রমে, বৈকল্পিকের জন্য বিভিন্ন পৃথক সম্ভাব্য মানের সংখ্যা খুব কম তাই আমি সহজভাবে একটি করতে পারি #if VARIABLE == nএবং সমস্ত ক্ষেত্রে আলাদাভাবে তালিকাবদ্ধ করতে পারি , তবে আমি ভাবছিলাম যে এটি করার কোনও চতুর উপায় আছে কিনা।


3
আপনি কি নিশ্চিত যে আপনি পরিবর্তে ফাংশন পয়েন্টার ব্যবহার করতে চান না?
গিরিগিরিস আন্দ্রেসেক

8
@ জুরিলি - ফাংশন পয়েন্টার রানটাইমে কাজ করে, প্রিপ্রসেসর সংকলনের সময় (আগে) কাজ করে। উভয় একই কাজের জন্য ব্যবহার করা যেতে পারে এমনকি যদি একটি পার্থক্য আছে।
ক্রিস লুটজ

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

2
পুনরায় খোলার জন্য ভোটদান কারণ এই প্রশ্নটি পুনরাবৃত্ত ম্যাক্রো প্রসারণ এবং স্ট্যাকওভারফ্লো.com/Qtionstions/216875/using-in- ম্যাক্রোগুলি সম্পর্কে নির্দিষ্ট "সাধারণ যা" এটি ভাল। "। এই প্রশ্নের শিরোনামটি আরও সুনির্দিষ্ট করা উচিত।
সিরো সান্তিলি 郝海东 冠状 病 六四 事件

আমি আশা করি এই উদাহরণটি হ্রাস করা হয়েছে: একই ঘটনা ঘটে #define A 0 \n #define M a ## A: দু'জনের ##থাকা মুখ্য নয়।
সিরো সান্তিলি 郝海东 冠状 病 六四 事件

উত্তর:


223

স্ট্যান্ডার্ড সি প্রিপ্রেসেসর

$ cat xx.c
#define VARIABLE 3
#define PASTER(x,y) x ## _ ## y
#define EVALUATOR(x,y)  PASTER(x,y)
#define NAME(fun) EVALUATOR(fun, VARIABLE)

extern void NAME(mine)(char *x);
$ gcc -E xx.c
# 1 "xx.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "xx.c"





extern void mine_3(char *x);
$

ইন্ডিরিশনের দুটি স্তর

অন্য উত্তরের মন্তব্যে ক্যাড রক্স জিজ্ঞাসা করলেন কেন এটি দুটি স্তরের ইন্ডিয়ারেশন প্রয়োজন। উল্টাপাল্টা উত্তর হ'ল স্ট্যান্ডার্ডটির এটির জন্য এটির প্রয়োজন হয়; আপনি স্ট্রিংাইজিং অপারেটরের সাথে সমতুল্য কৌশলও প্রয়োজন তা খুঁজে বের করার প্রবণতা।

সি 99 স্ট্যান্ডারের বিভাগ 6.10.3 'ম্যাক্রো রিপ্লেসমেন্ট', এবং 6.10.3.1 কে 'যুক্তি প্রতিস্থাপন' কভার করে।

কোনও ফাংশনের মতো ম্যাক্রোর অনুরোধের জন্য যুক্তিগুলি চিহ্নিত হওয়ার পরে, যুক্তি প্রতিস্থাপন ঘটে। প্রতিস্থাপন তালিকার একটি প্যারামিটার, যদি না পূর্বের #বা ##প্রাক প্রসেসিং টোকেন বা ##প্রাকপ্রসেসিং টোকেন (নীচে দেখুন) এর পরে থাকে তবে এতে যুক্ত সমস্ত ম্যাক্রো প্রসারিত হওয়ার পরে সংশ্লিষ্ট যুক্তি দ্বারা প্রতিস্থাপন করা হয়। প্রতিস্থাপিত হওয়ার আগে, প্রতিটি যুক্তির প্রিপ্র্রোসেসিং টোকেনগুলি পুরো ম্যাক্রোকে প্রতিস্থাপন করা হয় যেন তারা বাকি প্রিপ্রসেসিং ফাইলটি গঠন করে; অন্য কোনও প্রিপ্র্রোসেসিং টোকেন উপলব্ধ নেই।

অনুরোধে NAME(mine)যুক্তিটি 'আমার'; এটি পুরোপুরি 'আমার' তে প্রসারিত; এরপরে এটি প্রতিস্থাপনের স্ট্রিংয়ে প্রতিস্থাপন করা হয়:

EVALUATOR(mine, VARIABLE)

এখন ম্যাক্রো মূল্যায়নকারীকে আবিষ্কার করা হয়েছে, এবং যুক্তিগুলি 'আমার' এবং 'বৈকল্পিক' হিসাবে পৃথক করা হয়েছে; তারপরেরটি পুরোপুরি '3' এ প্রসারিত হবে এবং প্রতিস্থাপনের স্ট্রিংয়ের পরিবর্তে এটি করা যাবে:

PASTER(mine, 3)

এর ক্রিয়াকলাপটি অন্যান্য বিধি দ্বারা আবৃত (6.10.3.3 '' ## অপারেটর '):

যদি, কোনও ফাংশনের মতো ম্যাক্রোর প্রতিস্থাপনের তালিকায়, একটি প্যারামিটার তত্ক্ষণাত্ পূর্ববর্তী বা ##প্রাক প্রসেসিং টোকেন দ্বারা অনুসরণ করা হয় , তবে প্যারামিটারটি যুক্তিযুক্ত প্রিপ্রোসেসিং টোকেন ক্রম দ্বারা প্রতিস্থাপিত হয়; [...]

উভয় অবজেক্টের মতো এবং ফাংশন-জাতীয় ম্যাক্রো অনুরোধগুলির জন্য, প্রতিস্থাপনের তালিকাটি আরও ম্যাক্রোর নাম প্রতিস্থাপনের জন্য পুনরায় পরীক্ষা করার আগে প্রতিস্থাপন তালিকার ##প্রিপ্রোসেসিং টোকেনের প্রতিটি উদাহরণ মুছে ফেলা হয় এবং পূর্ববর্তী প্রিপ্রোসেসিং টোকনকে সংযুক্ত করা হয় নিম্নলিখিত প্রিপ্রোসেসিং টোকেন সহ।

সুতরাং, প্রতিস্থাপন তালিকা রয়েছে xদ্বারা অনুসরণ ##এবং ##অনুসরণ y; তাহলে আমাদের আছে:

mine ## _ ## 3

এবং ##টোকেনগুলি অপসারণ করে এবং উভয় পক্ষের টোকেনগুলি সংহত করে ফলন করার জন্য 'খনি' কে '_' এবং '3' এর সাথে একত্রিত করে:

mine_3

এই কাঙ্ক্ষিত ফলাফল।


যদি আমরা মূল প্রশ্নটি দেখি তবে কোডটি ছিল ('কিছু' ফাংশন'-এর পরিবর্তে 'খনি' ব্যবহারের জন্য অভিযোজিত):

#define VARIABLE 3
#define NAME(fun) fun ## _ ## VARIABLE

NAME(mine)

NAME- এর পক্ষে যুক্তিটি পরিষ্কারভাবে 'আমার' এবং এটি পুরোপুরি প্রসারিত।
6.10.3.3 এর নিয়ম অনুসরণ করে আমরা পাই:

mine ## _ ## VARIABLE

যা ##অপারেটরগুলি বাদ দিলে মানচিত্রগুলি:

mine_VARIABLE

ঠিক যেমন প্রশ্নে রিপোর্ট করা হয়েছে।


Ditionতিহ্যবাহী সি প্রিপ্রেসেসর

রবার্ট রাজার জিজ্ঞাসা করেছেন :

টোকেন পেস্টিং অপারেটর নেই এমন traditionalতিহ্যবাহী সি প্রিপ্রোসেসর দিয়ে কি কোনও উপায় আছে ##?

হতে পারে, এবং নাও হতে পারে - এটি প্রিপ্রোসেসরের উপর নির্ভর করে। স্ট্যান্ডার্ড প্রিপ্রোসেসর এর একটি সুবিধা হ'ল এটিতে এই সুবিধাটি রয়েছে যা নির্ভরযোগ্যভাবে কাজ করে, অন্যদিকে প্রাক-প্রাক প্রিপ্রসেসরগুলির জন্য বিভিন্ন বাস্তবায়ন ছিল। একটি প্রয়োজনীয়তা হ'ল প্রিপ্রোসেসর যখন কোনও মন্তব্যে প্রতিস্থাপন করে তখন এটি কোনও স্থান তৈরি করে না কারণ এএনএসআই প্রিপ্রসেসর করতে হয়। জিসিসি (.3.৩.০) সি প্রিপ্রসেসর এই প্রয়োজনীয়তা পূরণ করে; এক্সকোড 8.2.1 এর ক্ল্যাং প্রিপ্রসেসরটি তা করে না।

যখন এটি কাজ করে, এটি কাজটি করে ( x-paste.c):

#define VARIABLE 3
#define PASTE2(x,y) x/**/y
#define EVALUATOR(x,y) PASTE2(PASTE2(x,_),y)
#define NAME(fun) EVALUATOR(fun,VARIABLE)

extern void NAME(mine)(char *x);

মনে রাখবেন fun,এবং এর মধ্যে কোনও স্থান নেই VARIABLE- এটি গুরুত্বপূর্ণ কারণ যদি উপস্থিত থাকে তবে এটি আউটপুটে অনুলিপি করা হয় এবং আপনি mine_ 3নাম হিসাবে শেষ করেন যা অবশ্যই সিন্ট্যাক্টিকভাবে বৈধ নয়। (এখন, দয়া করে আমি কি আমার চুল ফিরে পেতে পারি?)

জিসিসি 6.3.0 (চলমান cpp -traditional x-paste.c) সহ, আমি পেয়েছি:

# 1 "x-paste.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "x-paste.c"





extern void mine_3(char *x);

এক্সকোড 8.2.1 থেকে কলঙ্ক সহ, আমি পেয়েছি:

# 1 "x-paste.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 329 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "x-paste.c" 2





extern void mine _ 3(char *x);

এই স্পেসগুলি সবকিছু লুণ্ঠন করে। আমি লক্ষ করি যে উভয় প্রিপ্রসেসরগুলি সঠিক; বিভিন্ন প্রাক-মানসম্পন্ন প্রিপ্রোসেসর উভয় আচরণকেই প্রদর্শন করেছিল, যা পোর্ট কোড দেওয়ার সময় টোকনকে একটি অত্যন্ত বিরক্তিকর এবং অবিশ্বাস্য প্রক্রিয়াযুক্ত করে তোলে। ##স্বরলিপি সহ মানটি মূলত এটিকে সহজতর করে।

এটি করার অন্যান্য উপায়ও থাকতে পারে। তবে, এটি কাজ করে না:

#define VARIABLE 3
#define PASTER(x,y) x/**/_/**/y
#define EVALUATOR(x,y) PASTER(x,y)
#define NAME(fun) EVALUATOR(fun,VARIABLE)

extern void NAME(mine)(char *x);

জিসিসি উত্পন্ন:

# 1 "x-paste.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "x-paste.c"





extern void mine_VARIABLE(char *x);

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


1
হ্যাঁ, এটি সমস্যার সমাধান করে। আমি দুটি স্তরের পুনরাবৃত্তি নিয়ে কৌশলটি জানতাম - আমাকে কমপক্ষে একবার স্ট্রিংফিকেশন দিয়ে খেলতে হয়েছিল - তবে কীভাবে এটি করতে হয় তা জানতাম না।
জেজে।

টোকেন পেস্টিং অপারেটর নেই # traditionalতিহ্যবাহী সি প্রিপ্রোসেসর দিয়ে কি এর কোন উপায় আছে?
রবার্ট রাজার

1
@ রবার্টরেজার: এটি উত্তরের দৈর্ঘ্য দ্বিগুণ করেছে, তবে আমি কভার করার জন্য তথ্য যুক্ত করেছি cpp -traditional। মনে রাখবেন যে এখানে একটি নির্দিষ্ট উত্তর নেই - এটি আপনার প্রাপ্ত প্রিপ্রোসেসরটির উপর নির্ভর করে।
জোনাথন লেফলার

উত্তরের জন্য আপনাকে অনেক ধন্যবাদ। এটি সম্পূর্ণ দুর্দান্ত! এর মধ্যে আমি আরও একটি ভিন্ন সমাধান খুঁজে পেয়েছি found এখানে দেখুন । এটির সমস্যাও রয়েছে যে এটি ঝাঁকুনির সাথে কাজ করে না। ভাগ্যক্রমে এটি আমার আবেদনের জন্য সমস্যা নয় ...
রবার্ট রাজার

32
#define VARIABLE 3
#define NAME2(fun,suffix) fun ## _ ## suffix
#define NAME1(fun,suffix) NAME2(fun,suffix)
#define NAME(fun) NAME1(fun,VARIABLE)

int NAME(some_function)(int a);

সত্য, আপনি কেন জানতে চান তা জানতে চান না। এটি কেন কাজ করে তা যদি আপনি জানেন তবে আপনি কাজের লোকটি হয়ে উঠবেন যিনি এই ধরণের জিনিস জানেন এবং প্রত্যেকে আপনাকে প্রশ্ন জিজ্ঞাসা করবেন। =)

সম্পাদনা করুন: আপনি যদি এটি কেন কাজ করে তা যদি সত্যিই জানতে চান তবে আমি আনন্দের সাথে একটি ব্যাখ্যা পোস্ট করব, কেউ ধরে নিবে যে আমাকে এতে মারবে না।


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