সি তে ফাংশন পয়েন্টারগুলির জন্য টাইপডেফগুলি বোঝা


237

যুক্তিযুক্ত ফাংশনগুলিতে পয়েন্টারগুলির জন্য টাইপডেফগুলিতে অন্যান্য লোকের কোড পড়লে আমি সর্বদা কিছুটা স্ট্যাম্পড ছিলাম। আমার মনে আছে যে সিটিতে কিছুক্ষণ আগে লেখা একটি সংখ্যার অ্যালগরিদম বোঝার চেষ্টা করার সময় এই জাতীয় সংজ্ঞাটি পেতে আমার কিছুটা সময় লেগেছে। সুতরাং, কীভাবে আপনি কার্যকারিতাগুলিতে পয়েন্টারগুলির জন্য (কী করণীয় এবং কী না) ভাল টাইপডেফগুলি লিখবেন সে সম্পর্কে আপনার টিপস এবং চিন্তাভাবনাগুলি ভাগ করে নিতে পারেন, কেন সেগুলি কার্যকর এবং অন্যের কাজ কীভাবে বোঝা যায়? ধন্যবাদ!


1
আপনি কিছু উদাহরণ প্রদান করতে পারেন?
আর্টেলিয়াস

2
আপনি কি ফাংশন পয়েন্টারগুলির জন্য ম্যাক্রোর পরিবর্তে ফাংশন পয়েন্টারগুলির জন্য টাইপডেফগুলি বোঝাতে চাইছেন না? আমি আগেরটি দেখেছি কিন্তু পরে নেই।
dave4420

উত্তর:


296

signal()সি স্ট্যান্ডার্ড থেকে ফাংশনটি বিবেচনা করুন :

extern void (*signal(int, void(*)(int)))(int);

পুরোপুরি অস্পষ্টভাবে সুস্পষ্ট - এটি এমন একটি ফাংশন যা দুটি আর্গুমেন্ট গ্রহণ করে, একটি পূর্ণসংখ্যা এবং একটি ফাংশনটিতে একটি ফাংশন যা একটি পূর্ণসংখ্যা হিসাবে যুক্তি হিসাবে গ্রহণ করে এবং কিছুই দেয় না, এবং এটি ( signal()) একটি ফাংশনটিতে একটি পয়েন্টার দেয় যা একটি পূর্ণসংখ্যা হিসাবে যুক্তি হিসাবে গ্রহণ করে এবং প্রত্যাবর্তন করে কিছুই নেই।

আপনি যদি লিখেন:

typedef void (*SignalHandler)(int signum);

তারপরে আপনি এর পরিবর্তে ঘোষণা করতে পারেন signal():

extern  SignalHandler signal(int signum, SignalHandler handler);

এর অর্থ একই জিনিস, তবে সাধারণত এটি পড়া সহজতর হিসাবে বিবেচিত হয়। এটি স্পষ্ট যে ফাংশনটি একটি intএবং a নেয় এবং a SignalHandlerফেরত দেয় SignalHandler

যদিও অভ্যস্ত হতে খানিকটা সময় নেয়। একটি জিনিস যা আপনি করতে পারবেন না তা হ'ল SignalHandler typedefফাংশন সংজ্ঞাটিতে একটি সিগন্যাল হ্যান্ডলার ফাংশন লিখুন ।

আমি এখনও সেই পুরানো-বিদ্যালয়ের মধ্যে রয়েছি যা কোনও ফাংশন পয়েন্টার হিসাবে এইভাবে প্রার্থনা করতে পছন্দ করে:

(*functionpointer)(arg1, arg2, ...);

আধুনিক সিনট্যাক্সটি কেবলমাত্র ব্যবহার করে:

functionpointer(arg1, arg2, ...);

কেন এটি কাজ করে তা আমি দেখতে পাচ্ছি - আমি কেবল এটি জানাতে পছন্দ করি যে ডাকা ফাংশনটির পরিবর্তে ভেরিয়েবলটি আরম্ভ করা হয়েছে সেখানে আমার সন্ধান করা দরকার functionpointer


স্যাম মন্তব্য করেছেন:

আমি এই ব্যাখ্যা আগে দেখেছি। এবং তারপরে, এখনকার মতো, আমার মনে হয় যা আমি পেলাম না তা ছিল দুটি বক্তব্যের মধ্যে সংযোগ:

    extern void (*signal(int, void()(int)))(int);  /*and*/

    typedef void (*SignalHandler)(int signum);
    extern SignalHandler signal(int signum, SignalHandler handler);

বা, আমি যা জানতে চাই তা হ'ল কোনটি আপনার ব্যবহারের দ্বিতীয় সংস্করণটি সামনে আসতে ব্যবহার করতে পারে তা অন্তর্নিহিত ধারণাটি কী? "সিগন্যালহ্যান্ডলার" এবং প্রথম টাইপিডেফকে সংযোগকারী এমন মৌলিকটি কী? আমি মনে করি যে এখানে যা বোঝানোর দরকার তা হ'ল টাইপয়েড আসলে এখানে যা করছে।

আবার চেষ্টা করা যাক. এর মধ্যে প্রথমটি সরাসরি সি স্ট্যান্ডার্ড থেকে তুলে নেওয়া হয়েছে - আমি এটি পুনরায় টাইপ করেছিলাম এবং পরীক্ষা করেছিলাম যে আমার প্রথম বন্ধনী ছিল (আমি এটি সংশোধন না করা পর্যন্ত নয় - এটি মনে রাখা শক্ত কুকি)।

প্রথমত, মনে রাখবেন যে typedefএকটি প্রকারের জন্য একটি উপাধিকার পরিচয় করিয়ে দেয়। সুতরাং, উপনামটি হ'ল SignalHandlerএবং এর ধরণটি হ'ল:

একটি ক্রিয়াকলাপের জন্য একটি পয়েন্টার যা আর্গুমেন্ট হিসাবে একটি পূর্ণসংখ্যার গ্রহণ করে এবং কিছুই দেয় না।

'রিটার্ন কিছুই না' অংশ বানানযুক্ত void; যে যুক্তিটি একটি পূর্ণসংখ্যা হয় তা (আমি বিশ্বাস করি) স্ব-ব্যাখ্যামূলক। নিম্নলিখিত স্বরলিপিটি কেবল (বা না) সুনির্দিষ্টভাবে আর্গুমেন্টগুলি নির্দিষ্ট করার জন্য এবং প্রদত্ত প্রকারটি ফেরত দেওয়ার জন্য সি বানান কীভাবে নির্দেশ করে:

type (*function)(argtypes);

সিগন্যাল হ্যান্ডলার ধরণের তৈরি করার পরে, আমি এটি ভেরিয়েবলগুলি ঘোষণা করতে ব্যবহার করতে পারি এবং আরও কিছু করতে। উদাহরণ স্বরূপ:

static void alarm_catcher(int signum)
{
    fprintf(stderr, "%s() called (%d)\n", __func__, signum);
}

static void signal_catcher(int signum)
{
    fprintf(stderr, "%s() called (%d) - exiting\n", __func__, signum);
    exit(1);
}

static struct Handlers
{
    int              signum;
    SignalHandler    handler;
} handler[] =
{
    { SIGALRM,   alarm_catcher  },
    { SIGINT,    signal_catcher },
    { SIGQUIT,   signal_catcher },
};

int main(void)
{
    size_t num_handlers = sizeof(handler) / sizeof(handler[0]);
    size_t i;

    for (i = 0; i < num_handlers; i++)
    {
        SignalHandler old_handler = signal(handler[i].signum, SIG_IGN);
        if (old_handler != SIG_IGN)
            old_handler = signal(handler[i].signum, handler[i].handler);
        assert(old_handler == SIG_IGN);
    }

    ...continue with ordinary processing...

    return(EXIT_SUCCESS);
}

দয়া করে নোট করুন কীভাবে printf()সিগন্যাল হ্যান্ডলারের সাহায্যে এড়ানো যায় ?

সুতরাং, আমরা এখানে কী করেছি - 4 টি স্ট্যান্ডার্ড শিরোনাম বাদ দিয়ে কোডটি পরিষ্কারভাবে সংকলন করার জন্য প্রয়োজন হবে?

প্রথম দুটি ফাংশন হ'ল ফাংশন যা একটি একক পূর্ণসংখ্যা নেয় এবং কিছুই দেয় না। এর মধ্যে একটি প্রকৃতপক্ষে একেবারে ধন্যবাদ জানায় exit(1);না অন্যটি বার্তা প্রিন্ট করার পরে ফিরে আসে। সচেতন হন যে সি স্ট্যান্ডার্ড আপনাকে সিগন্যাল হ্যান্ডলারের ভিতরে খুব বেশি অনুমতি দেয় না; পজিক্স যা অনুমোদিত তা কিছুটা উদার, তবে আনুষ্ঠানিকভাবে কলিং অনুমোদন করে না fprintf()। আমি প্রাপ্ত সিগন্যাল নম্বরটিও মুদ্রণ করি। ইন alarm_handler()ফাংশন, মান সবসময় হতে হবে SIGALRMযেমন যে শুধুমাত্র সংকেত যে এটির জন্য একটি হ্যান্ডলার, কিন্তু signal_handler()পেতে পারে SIGINTবা SIGQUITসংকেত নম্বর হিসাবে কারণ একই ফাংশন উভয়ের জন্য ব্যবহার করা হয়।

তারপরে আমি স্ট্রাকচারের একটি অ্যারে তৈরি করি, যেখানে প্রতিটি উপাদান একটি সিগন্যাল নম্বর এবং সেই সংকেতের জন্য ইনস্টল করার জন্য হ্যান্ডলার সনাক্ত করে। আমি 3 সিগন্যাল সম্পর্কে চিন্তা করতে বেছে নিয়েছি; আমি প্রায়ই চিন্তা চাই SIGHUP, SIGPIPEএবং SIGTERMখুব এবং প্রায় কিনা তারা (সংজ্ঞায়িত করা হয় #ifdefশর্তাধীন সংকলন), কিন্তু যে শুধু কিছু complicates। আমি সম্ভবত এর sigaction()পরিবর্তে পসিক্স ব্যবহার করবsignal() তবে এটি অন্য সমস্যা; আসুন আমরা যা শুরু করেছিলাম তার সাথে লেগে থাকি।

main()হ্যান্ডেলার তালিকাটির ফাংশন iterates ইনস্টল করার জন্য। প্রতিটি হ্যান্ডলারের জন্য, signal()প্রক্রিয়াটি বর্তমানে সংকেতটিকে অগ্রাহ্য করছে কিনা তা অনুসন্ধান করার জন্য প্রথমে এটি কল করে এবং এটি করার সময় SIG_IGNহ্যান্ডলার হিসাবে ইনস্টল করে, যা সিগন্যালটিকে অবহেলা করে তা নিশ্চিত করে। যদি সিগন্যালটি আগে উপেক্ষা করা হত না, তবে এটি তখন signal()পছন্দসই সংকেত হ্যান্ডলারটি ইনস্টল করার জন্য আবার কল করে । (অন্যান্য মান সম্ভবতঃ হয় SIG_DFL, সিগন্যাল জন্য ডিফল্ট সংকেত হ্যান্ডলার।) এর প্রথম কল 'সংকেত ()' থেকে হ্যান্ডলার সেট কারণ SIG_IGNএবং signal()পূর্ববর্তী ত্রুটি হ্যান্ডলার, এর মান oldপরif বিবৃতি হতে হবে SIG_IGNঅত: পর কথন -। (ভাল, এটা হতে পারে)SIG_ERR যদি কিছু নাটকীয়ভাবে ভুল হয়ে যায় - তবে আমি দৃ firing়তার সাথে গুলি চালানো থেকে এটি শিখতে পারি))

প্রোগ্রামটি তখন তার স্টাফগুলি করে এবং স্বাভাবিকভাবে প্রস্থান করে।

নোট করুন যে কোনও ফাংশনের নামটি উপযুক্ত প্রকারের কোনও ফাংশনের পয়েন্টার হিসাবে বিবেচনা করা যেতে পারে। আপনি যখন ফাংশন-কল বন্ধনী প্রয়োগ না করেন - যেমন প্রাথমিক হিসাবে যেমন - ফাংশনটির নামটি একটি ফাংশন পয়েন্টার হয়ে যায়। এটি pointertofunction(arg1, arg2)স্বরলিপি দ্বারা ফাংশন প্রার্থনা করা যুক্তিসঙ্গত কেন এ কারণেই ; আপনি যখন দেখবেন alarm_handler(1), আপনি alarm_handlerএটি ফাংশনের পয়েন্টার হিসাবে বিবেচনা করতে পারেন এবং তাই alarm_handler(1)ফাংশন পয়েন্টারের মাধ্যমে কোনও ফাংশনটির অনুরোধ।

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

এখন আমরা আবার প্রশ্নটিতে ফিরে যাই - কীভাবে দুটি ঘোষণাপত্র signal()একে অপরের সাথে সম্পর্কিত।

আসুন দ্বিতীয় ঘোষণাটি পর্যালোচনা করুন:

 extern SignalHandler signal(int signum, SignalHandler handler);

আমরা যদি ফাংশনের নাম এবং প্রকারটি পরিবর্তন করি তবে:

 extern double function(int num1, double num2);

এটিকে একটি ফাংশন হিসাবে ব্যাখ্যা করার ক্ষেত্রে আপনার কোনও সমস্যা হবে না যা intএকটি doubleআর্গুমেন্ট হিসাবে গ্রহণ করে এবং একটি doubleমূল্য ফেরত দেয় (আপনি কি হতে পারেন যদি সমস্যাটি হয় তবে আপনি 'ফ্যাস' না করাই ভাল - তবে সম্ভবত প্রশ্নগুলি জিজ্ঞাসা করার বিষয়ে আপনাকে সতর্ক হওয়া উচিত) এই সমস্যা হিসাবে যদি এটি এক)।

এখন, একটি হওয়ার পরিবর্তে double, signal()ফাংশনটি এটিটিকে SignalHandlerতার দ্বিতীয় যুক্তি হিসাবে গ্রহণ করে এবং এটি তার ফলাফল হিসাবে এটি প্রদান করে।

যে যান্ত্রিকগুলি দ্বারা এটি হিসাবেও বিবেচনা করা যেতে পারে:

extern void (*signal(int signum, void(*handler)(int signum)))(int signum);

ব্যাখ্যা করা খুব জটিল - তাই আমি সম্ভবত এটি স্ক্রু আপ। এবার আমি প্যারামিটারের নাম দিয়েছি - যদিও নামগুলি সমালোচনামূলক নয়।

সাধারণভাবে, সি তে, ঘোষণা প্রক্রিয়াটি এমন যে আপনি যদি লিখেন:

type var;

তারপরে আপনি যখন varএটি লিখবেন তখন প্রদত্ত একটি মান উপস্থাপন করে type। উদাহরণ স্বরূপ:

int     i;            // i is an int
int    *ip;           // *ip is an int, so ip is a pointer to an integer
int     abs(int val); // abs(-1) is an int, so abs is a (pointer to a)
                      // function returning an int and taking an int argument

মান ইন, typedefব্যাকরণ একটি সংগ্রহস্থলের শ্রেণী হিসেবে গণ্য হবে, বরং ভালো staticএবং externস্টোরেজ শ্রেণীর হয়।

typedef void (*SignalHandler)(int signum);

এর অর্থ হ'ল আপনি যখন কোনও ভেরিয়েবল দেখতে পান SignalHandler(অ্যালার্ম_হ্যান্ডলার বলুন) হিসাবে আহ্বান জানানো হয়েছে:

(*alarm_handler)(-1);

ফলাফল আছে type void- কোন ফলাফল নেই। এবং যুক্তি সহ (*alarm_handler)(-1);একটি প্রার্থনা ।alarm_handler()-1

সুতরাং, যদি আমরা ঘোষণা করি:

extern SignalHandler alt_signal(void);

এর অর্থ হল:

(*alt_signal)();

একটি অকার্যকর মান উপস্থাপন করে। এবং সেইজন্য:

extern void (*alt_signal(void))(int signum);

সমতুল্য এখন signal()এটি আরও জটিল কারণ এটি কেবলমাত্র ফেরত দেয় না SignalHandler, এটি কোনও পূর্ববর্তী এবং একটি উভয়কেই SignalHandlerযুক্তি হিসাবে গ্রহণ করে :

extern void (*signal(int signum, SignalHandler handler))(int signum);

extern void (*signal(int signum, void (*handler)(int signum)))(int signum);

যদি তা এখনও আপনাকে বিভ্রান্ত করে, আমি কীভাবে সহায়তা করব তা নিশ্চিত নই - এটি এখনও কিছু স্তরের কাছে আমার কাছে রহস্যজনক তবে আমি কীভাবে এটি কাজ করে তা সম্পর্কে অভ্যস্ত হয়েছি এবং তাই আপনাকে বলতে পারি যে আপনি যদি আরও 25 বছর ধরে থাকেন তবে বা তাই, এটি আপনার দ্বিতীয় প্রকৃতির হয়ে উঠবে (এবং আপনি যদি চালাক হন তবে কিছুটা দ্রুতও হতে পারে)।


3
আমি এই ব্যাখ্যা আগে দেখেছি। এবং তারপরে, এখনকার মতো, আমার মনে হয় আমি যা পাইনি তা হ'ল দুটি বক্তব্যের মধ্যে সংযোগ ছিল: বহিরাগত শূন্যতা ( সিগন্যাল (ইনট, শূন্য ( ) (ইনট))) (ইনট); / * এবং * / টাইপডেফ অকার্যকর (* সিগন্যাল হ্যান্ডলার) (ইন সিগন্যাম); বাহ্যিক সিগন্যাল হ্যান্ডলার সিগন্যাল (ইন সিগন্যাম, সিগন্যাল হ্যান্ডলার হ্যান্ডলার); বা, আমি যা জানতে চাই তা হ'ল কোনটি আপনার ব্যবহারের দ্বিতীয় সংস্করণটি সামনে আসতে ব্যবহার করতে পারে তা অন্তর্নিহিত ধারণাটি কী? "সিগন্যালহ্যান্ডলার" এবং প্রথম টাইপিডেফকে সংযোগকারী এমন মৌলিকটি কী? আমি মনে করি যে এখানে যা বোঝানোর দরকার তা হ'ল টাইপেইফ আসলে এখানে যা করছে। ধন্যবা

6
দুর্দান্ত উত্তর, আমি এই সুতোটিতে ফিরে এসে আনন্দিত। আমি মনে করি না আমি সবকিছু বুঝি তবে একদিন আমি করব। এই কারণেই আমি এসও পছন্দ করি। ধন্যবাদ.
Toto

2
কেবল একটি নিট বেছে নেওয়া: একটি সিগন্যাল হ্যান্ডলারের ভিতরে প্রিন্টফ () এবং বন্ধুদের কল করা নিরাপদ নয়; প্রিন্টফ () পুনরায় প্রবেশকারী নয় (মূলত এটি
ম্যালোককে

4
এর extern void (*signal(int, void(*)(int)))(int);অর্থ হল signal(int, void(*)(int))ফাংশনটি একটি ফাংশন পয়েন্টারটিতে ফিরিয়ে দেবে void f(int)। আপনি যখন কোনও ফাংশন পয়েন্টারকে ফেরতের মান হিসাবে নির্দিষ্ট করতে চান , সিনট্যাক্সটি জটিল হয়ে যায়। আপনি বামদিকে রিটার্ন মানের ধরণ এবং যুক্তি তালিকার ডানদিকে রাখতে হবে , যখন এটি মধ্যস্থতাটি আপনি সংজ্ঞায়িত করছেন। এবং এই ক্ষেত্রে, signal()ফাংশনটি নিজেই এটির প্যারামিটার হিসাবে একটি ফাংশন পয়েন্টার নেয়, যা জিনিসগুলিকে আরও জটিল করে তোলে। সুসংবাদটি হ'ল, আপনি যদি এটি পড়তে পারেন তবে ফোর্স ইতিমধ্যে আপনার সাথে রয়েছে। :)।
smwikedia

1
&একটি ফাংশন নামের সামনে ব্যবহার সম্পর্কে পুরানো স্কুল কি ? এটি সম্পূর্ণ অপ্রয়োজনীয়; অর্থহীন, এমনকি। এবং অবশ্যই "পুরাতন স্কুল" নয়। পুরাতন স্কুল একটি ফাংশন নাম সাধারণ এবং সাধারণ ব্যবহার করে।
জোনাথন লেফলার

80

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

সুতরাং উদাহরণস্বরূপ ধরুন আপনার একটি ফাংশন রয়েছে:

float doMultiplication (float num1, float num2 ) {
    return num1 * num2; }

তারপরে নিম্নলিখিত টাইপিডেফ:

typedef float(*pt2Func)(float, float);

এই doMulitplicationফাংশনটি নির্দেশ করতে ব্যবহার করা যেতে পারে । এটি কেবল একটি ফাংশনটির জন্য একটি পয়েন্টার সংজ্ঞায়িত করছে যা একটি ফ্লোট ফেরত দেয় এবং দুটি পরামিতি নেয়, প্রতিটি টাইপ ভাসা। এই সংজ্ঞাটির বন্ধুত্বপূর্ণ নাম রয়েছে pt2Func। নোটটি যে pt2Funcকোনও ফাংশনকে নির্দেশ করতে পারে যা একটি ফ্লোট ফেরত দেয় এবং 2 টি ফ্লোট নেয়।

সুতরাং আপনি একটি পয়েন্টার তৈরি করতে পারেন যা ডোমলিটপ্লিকেশন ফাংশনটিকে নিম্নরূপে নির্দেশ করে:

pt2Func *myFnPtr = &doMultiplication;

এবং আপনি নিম্নলিখিত হিসাবে এই পয়েন্টার ব্যবহার করে ফাংশন প্রার্থনা করতে পারেন:

float result = (*myFnPtr)(2.0, 5.1);

এটি ভাল পঠন করে: http://www.newty.de/fpt/index.html


সাইকোটিক, ধন্যবাদ! এটা সহায়ক ছিল। ফাংশন পয়েন্টার ওয়েব পৃষ্ঠার লিঙ্কটি সত্যই সহায়ক। এখন এটি পড়া।

... তবে, সেই newty.de লিঙ্কটি মোটেও টাইপডেফস সম্পর্কে কথা বলতে দেখা যায় না :( সুতরাং যদিও লিঙ্কটি দুর্দান্ত তবে

11
আপনি ইতিমধ্যে একটি পয়েন্টার হিসাবে pt2Func myFnPtr = &doMultiplication;পরিবর্তে করতে চেয়েছিলেন । pt2Func *myFnPtr = &doMultiplication;myFnPtr
তামিলসেলভান

1
pt2Func * myFnPtr = & do মাল্টিপ্লিকেশন ঘোষণা; pt2Func এর পরিবর্তে myFnPtr = & doM Multiplication; একটি সতর্কতা নিক্ষেপ
আলফাগোকু

2
@ তমিলসেলভান সঠিক। myFunPtrইতিমধ্যে একটি ফাংশন পয়েন্টার তাই ব্যবহার করুনpt2Func myFnPtr = &doMultiplication;
ডাস্টিন বিসর

35

ফাংশন পয়েন্টারের টাইপডেফ বোঝার একটি খুব সহজ উপায়:

int add(int a, int b)
{
    return (a+b);
}

typedef int (*add_integer)(int, int); //declaration of function pointer

int main()
{
    add_integer addition = add; //typedef assigns a new variable i.e. "addition" to original function "add"
    int c = addition(11, 11);   //calling function via new variable
    printf("%d",c);
    return 0;
}

32

cdeclফাংশন পয়েন্টার ঘোষণার মতো অদ্ভুত সিনট্যাক্স বোঝার জন্য দুর্দান্ত সরঞ্জাম। এগুলি উত্পন্ন করতে আপনি এটি ব্যবহার করতে পারেন।

ভবিষ্যতের রক্ষণাবেক্ষণ (নিজের বা অন্যদের দ্বারা) জটিল ঘোষণাকে আরও সহজে পার্স করার জন্য টিপস হিসাবে, আমি typedefছোট ছোট অংশগুলি তৈরি করার এবং সেই ছোট ছোট টুকরোগুলি বৃহত্তর এবং আরও জটিল অভিব্যক্তির জন্য বিল্ডিং ব্লক হিসাবে ব্যবহার করার পরামর্শ দিচ্ছি । উদাহরণ স্বরূপ:

typedef int (*FUNC_TYPE_1)(void);
typedef double (*FUNC_TYPE_2)(void);
typedef FUNC_TYPE_1 (*FUNC_TYPE_3)(FUNC_TYPE_2);

বরং:

typedef int (*(*FUNC_TYPE_3)(double (*)(void)))(void);

cdecl এই জিনিসগুলি আপনাকে সাহায্য করতে পারে:

cdecl> explain int (*FUNC_TYPE_1)(void)
declare FUNC_TYPE_1 as pointer to function (void) returning int
cdecl> explain double (*FUNC_TYPE_2)(void)
declare FUNC_TYPE_2 as pointer to function (void) returning double
cdecl> declare FUNC_TYPE_3 as pointer to function (pointer to function (void) returning double) returning pointer to function (void) returning int
int (*(*FUNC_TYPE_3)(double (*)(void )))(void )

এবং (বাস্তবে) ঠিক কীভাবে আমি উপরের সেই ক্রেজি জগাখিচুড়ি তৈরি করেছি।


2
হাই কার্ল, এটি একটি অত্যন্ত অন্তর্দৃষ্টিপূর্ণ উদাহরণ এবং ব্যাখ্যা ছিল। এছাড়াও, cdecl ব্যবহার দেখানোর জন্য ধন্যবাদ। অনেক প্রশংসিত.

উইন্ডোজের জন্য কি সিডিসিএল আছে?
জ্যাক

@ জ্যাক, আমি নিশ্চিত আপনি এটি তৈরি করতে পারবেন, হ্যাঁ।
কার্ল নরম

2
রয়েছে cdecl.org যা সামর্থ্য কিন্তু অনলাইন একই সাজানোর প্রদান করে। আমাদের উইন্ডোজ বিকাশকারীদের জন্য দরকারী।
zaknotzach

12
int add(int a, int b)
{
  return (a+b);
}
int minus(int a, int b)
{
  return (a-b);
}

typedef int (*math_func)(int, int); //declaration of function pointer

int main()
{
  math_func addition = add;  //typedef assigns a new variable i.e. "addition" to original function "add"
  math_func substract = minus; //typedef assigns a new variable i.e. "substract" to original function "minus"

  int c = addition(11, 11);   //calling function via new variable
  printf("%d\n",c);
  c = substract(11, 5);   //calling function via new variable
  printf("%d",c);
  return 0;
}

এর ফলাফল:

22

6

মনে রাখবেন যে, উভয় ফাংশন ঘোষণার জন্য একই গণিত_ফঙ্ক প্রসিফার ব্যবহার করা হয়েছে।

টাইপিডেফের একই পদ্ধতির বহিরাগত কাঠামোর জন্য ব্যবহার করা যেতে পারে ((অন্য ফাইলে sturuct ব্যবহার করে))


5

আরও জটিল ধরণের যেমন ফাংশন পয়েন্টার সংজ্ঞায়িত করতে টাইপডেফ ব্যবহার করুন

আমি সি-তে একটি রাষ্ট্র-মেশিন সংজ্ঞায়নের উদাহরণ গ্রহণ করব

    typedef  int (*action_handler_t)(void *ctx, void *data);

এখন আমরা অ্যাকশন_হ্যান্ডলার নামে একটি ধরণ সংজ্ঞায়িত করেছি যা দুটি পয়েন্টার নেয় এবং একটি পূর্বাবস্থায় ফিরে আসে

আপনার রাষ্ট্র-মেশিন সংজ্ঞায়িত করুন

    typedef struct
    {
      state_t curr_state;   /* Enum for the Current state */
      event_t event;  /* Enum for the event */
      state_t next_state;   /* Enum for the next state */
      action_handler_t event_handler; /* Function-pointer to the action */

     }state_element;

ক্রিয়াটির ফাংশন পয়েন্টারটি একটি সাধারণ প্রকারের মতো দেখায় এবং টাইপিডেফ প্রাথমিকভাবে এই উদ্দেশ্যে কাজ করে।

আমার সমস্ত ইভেন্ট হ্যান্ডলারের এখন অ্যাকশন_হ্যান্ডলারের দ্বারা সংজ্ঞায়িত ধরণটি মেনে চলা উচিত

    int handle_event_a(void *fsm_ctx, void *in_msg );

    int handle_event_b(void *fsm_ctx, void *in_msg );

তথ্যসূত্র:

লিন্ডেন দ্বারা বিশেষজ্ঞ সি প্রোগ্রামিং


4

এটি ফাংশন পয়েন্টার এবং ফাংশন পয়েন্টার অ্যারের সহজতম উদাহরণ যা আমি অনুশীলন হিসাবে লিখেছি।

    typedef double (*pf)(double x);  /*this defines a type pf */

    double f1(double x) { return(x+x);}
    double f2(double x) { return(x*x);}

    pf pa[] = {f1, f2};


    main()
    {
        pf p;

        p = pa[0];
        printf("%f\n", p(3.0));
        p = pa[1];
        printf("%f\n", p(3.0));
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.