সি ডিফল্ট আর্গুমেন্ট


279

সি-তে কোনও ফাংশনে ডিফল্ট আর্গুমেন্ট নির্দিষ্ট করার কোনও উপায় আছে কি?


6
সি ++ নয়, কিছুটা উন্নত সি চাই। সি + ভাবেন। বিভিন্ন ধরণের ছোট ছোট উন্নতি সি ++ থেকে তোলা হয়েছে, তবে বড় গণ্ডগোল নয়। এবং, দয়া করে, কোনও আলাদা লিঙ্ক-লোডার নেই। অন্য একটি প্রাক প্রসেসরের মতো ধাপ হওয়া উচিত। আদর্শায়িত। সর্বত্র ...
ivo ওয়েলচ

সম্পর্কিত প্রশ্ন যা আমি পাশের বারে তালিকাভুক্ত দেখিনি।
শেলবি মুর তৃতীয়

আমি বলতে চাই যে বর্বর হওয়া বন্ধ করুন এবং সি ++ (11, ...) ভাল ব্যবহার করতে শিখুন - জে কে! / আমি শিখার আগুন জ্বালিয়ে দিই ... তবে ... তুমি এটাকে ভালবাসতে আসবে ... হাহাহা আমি নিজেকে সাহায্য করতে পারি না, দুঃখিত।
মুডবুম

উত্তর:


147

আসলে তা না. একমাত্র উপায় হ'ল একটি ভারার্গস ফাংশন লিখুন এবং ম্যানুয়ালি ডিফল্ট মানগুলি আর্গুমেন্টগুলির জন্য পূরণ করুন যা কলার পাস করেন না।


22
আমি ভারার্গস ব্যবহার করার সময় পরীক্ষার অভাবকে ঘৃণা করি।
ডিএমকেকে --- প্রাক্তন মডারেটর বিড়ালছানা

16
পাশাপাশি আপনার উচিত; আমি আসলে এটি সুপারিশ করি না; আমি কেবল জানাতে চেয়েছিলাম যে এটি সম্ভব।
এলি কোর্টরাইট 15

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

3
open(2)সিস্টেম কল একটি ঐচ্ছিক যুক্তি যে প্রয়োজনীয় আর্গুমেন্ট উপর নির্ভর করে উপস্থিত হতে পারে এই ব্যবহার করে এবং printf(3)একটি বিন্যাসে স্ট্রিংটি নির্দিষ্ট করে কতগুলি আর্গুমেন্ট থাকবে পড়ে। উভয়ই বেশ নিরাপদে এবং কার্যকরভাবে ভ্যারাগগুলি ব্যবহার করে এবং আপনি অবশ্যই এগুলি স্ক্রু করতে পারেন, printf()বিশেষত বেশ জনপ্রিয় বলে মনে হচ্ছে।
ক্রিস লুটজ

4
@ এলি: সমস্ত সি সংকলক জিসিসি নয়। আপনার প্রিন্টফ () আর্টসগুলি আপনার ফর্ম্যাট স্ট্রিংয়ের সাথে মেলে না, তখন এটি সতর্ক করতে কিছু উন্নত সংকলক যাদু চলছে। এবং আমি মনে করি না যে আপনার নিজস্ব বৈকল্পিক ফাংশনগুলির জন্য অনুরূপ সতর্কতা পাওয়া সম্ভব (যদি না তারা বিন্যাসের স্ট্রিংয়ের একই স্টাইল ব্যবহার করে)।
টমলোগিক

280

বাহ, সবাই এখানে আশেপাশের হতাশাবাদী। উত্তরটি হল হ্যাঁ.

এটি তুচ্ছ নয়: শেষ অবধি, আমাদের মূল ফাংশন, একটি সমর্থনকারী কাঠামো, একটি মোড়ক ফাংশন এবং মোড়ক ফাংশনটির চারপাশে একটি ম্যাক্রো থাকবে। আমার কাজটিতে এই সমস্ত স্বয়ংক্রিয় করার জন্য আমার কাছে ম্যাক্রোগুলির একটি সেট রয়েছে; একবার আপনি প্রবাহটি বুঝতে পারলে আপনার পক্ষে এটি করা সহজ হবে।

আমি এটি অন্য কোথাও লিখে রেখেছি, সুতরাং সংক্ষিপ্তসারটি পরিপূরক করতে এখানে একটি বিশদ বহিরাগত লিঙ্ক রয়েছে: http://modelingwithdata.org/arch/00000022.htm

আমরা ঘুরতে চাই

double f(int i, double x)

ডিফল্ট গ্রহণ করে এমন কোনও ক্রিয়াতে (i = 8, x = 3.14) একটি সহযোগী কাঠামো সংজ্ঞায়িত করুন:

typedef struct {
    int i;
    double x;
} f_args;

আপনার ফাংশনটির নতুন নাম দিন f_base, এবং একটি মোড়ক ফাংশন সংজ্ঞায়িত করুন যা ডিফল্ট সেট করে এবং বেসকে কল করে:

double var_f(f_args in){
    int i_out = in.i ? in.i : 8;
    double x_out = in.x ? in.x : 3.14;
    return f_base(i_out, x_out);
}

এখন সি এর ভেরিয়েডিক ম্যাক্রোগুলি ব্যবহার করে একটি ম্যাক্রো যুক্ত করুন। এইভাবে ব্যবহারকারীদের জানতে হবে না যে তারা প্রকৃতপক্ষে কোনও f_argsকাঠামো তৈরি করছে এবং তারা মনে করে যে তারা সাধারনত করছে:

#define f(...) var_f((f_args){__VA_ARGS__});

ঠিক আছে, এখন নিম্নলিখিত সমস্ত কাজ করবে:

f(3, 8);      //i=3, x=8
f(.i=1, 2.3); //i=1, x=2.3
f(2);         //i=2, x=3.14
f(.x=9.2);    //i=8, x=9.2

যৌগিক আরম্ভকারীরা সঠিক বিধিগুলির জন্য কীভাবে ডিফল্ট সেট করে তার বিধিগুলি পরীক্ষা করে দেখুন।

একটি জিনিস যা কাজ করবে না: f(0)কারণ আমরা অনুপস্থিত মান এবং শূন্যের মধ্যে পার্থক্য করতে পারি না। আমার অভিজ্ঞতা হিসাবে, এটি সন্ধান করার মতো কিছু, তবে প্রয়োজন দেখাশোনা করা যেতে পারে --- আপনার ডিফল্টটি সত্যই শূন্যের অর্ধেক সময়।

আমি এটি লেখার সমস্যায় পড়েছি কারণ আমি মনে করি নামযুক্ত যুক্তি এবং ডিফল্টগুলি সি তে কোডিংকে আরও সহজ এবং আরও মজাদার করে তোলে। এবং সি এত সহজ হওয়ার জন্য এখনও দুর্দান্ত রয়েছে এবং এখনও এই সমস্ত সম্ভব করার পক্ষে যথেষ্ট পরিমাণে রয়েছে।


16
+1 সৃজনশীল! এটির সীমাবদ্ধতা রয়েছে তবে এটি টেবিলে নামকরণকৃত প্যারামিটার নিয়ে আসে। মনে রাখবেন যে, {}(খালি আরম্ভকারী) একটি ত্রুটি C99।
u0b34a0f6ae

28
তবে, এখানে আপনার জন্য দুর্দান্ত কিছু: স্ট্যান্ডার্ডটি নামযুক্ত সদস্যদের একাধিকবার নির্দিষ্ট করে, পরে ওভাররাইড করে। সুতরাং নামযুক্ত-পরামিতিগুলির জন্য আপনি কেবল ডিফল্ট সমস্যা সমাধান করতে পারেন এবং খালি কল করার অনুমতি দিতে পারেন। #define vrange(...) CALL(range,(param){.from=1, .to=100, .step=1, __VA_ARGS__})
u0b34a0f6ae

3
আমি আশা করি সংকলক ত্রুটিগুলি পাঠযোগ্য, তবে এটি দুর্দান্ত কৌশল! প্রায় অজগর কোয়ার্গসের মতো দেখতে।
টোটোটো দুই

6
@ রুনহোল্ট অবশ্যই সহজ হলেও এটি বস্তুনিষ্ঠভাবে ভাল নয়; নামযুক্ত প্যারামিটারগুলি কলগুলির পাঠযোগ্যতার স্বাচ্ছন্দ্যের মতো সুবিধা (সোর্স কোডের পাঠযোগ্যতার ব্যয়ে) আসে with একটি উত্স বিকাশকারীদের জন্য ভাল, অন্যটি ফাংশন ব্যবহারকারীদের জন্য ভাল। "এটি আরও ভাল!"
এলিস

3
@ ডেভিডপি: সি 11 7..9.৯ (১৯), সংস্থাগুলি সূচনা করার সময়: "সমস্ত সাবওজেক্টস যা স্পষ্টভাবে সূচনা করা হয় নি সেগুলি স্ট্যাটিক স্টোরেজ সময়কালের অবজেক্টগুলির মতো স্পষ্টভাবে সূচনা করা হবে" এবং আপনি জানেন যে, স্থির-সময়কাল উপাদানগুলি শূন্যে আরম্ভ করা হবে | শূন্য | \ 0। [এটি সি 99 এও ছিল]]
বি কে k

161

হ্যাঁ. :-) তবে এমনভাবে নয় যা আপনি আশা করতে পারেন।

int f1(int arg1, double arg2, char* name, char *opt);

int f2(int arg1, double arg2, char* name)
{
  return f1(arg1, arg2, name, "Some option");
}

দুর্ভাগ্যক্রমে, সি আপনাকে ওভারলোড পদ্ধতিগুলিতে অনুমতি দেয় না যাতে আপনি দুটি ভিন্ন ফাংশন দিয়ে শেষ করতে পারেন। তবুও, f2 কল করে আপনি আসলে একটি ডিফল্ট মান দিয়ে কল করতে পারবেন। এটি একটি "নিজেকে পুনরাবৃত্তি করবেন না" সমাধান, যা আপনাকে বিদ্যমান কোড অনুলিপি / আটকানো এড়াতে সহায়তা করে।


24
এফডাব্লুআইডাব্লু, আমি গ্রহণ করা অর্গগুলির সংখ্যাটি চিহ্নিত করতে ফাংশনটির শেষে নম্বরটি ব্যবহার করতে পছন্দ করব। যেকোন স্বেচ্ছাসেবী সংখ্যা ব্যবহার না করে এটি আরও সহজ করে তোলে। :)
ম্যাক

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


41

আমরা ফাংশন তৈরি করতে পারি যা ডিফল্ট মানগুলির জন্য নামযুক্ত পরামিতিগুলি (কেবল) ব্যবহার করে। এটি বিকে.র উত্তরের ধারাবাহিকতা।

#include <stdio.h>                                                               

struct range { int from; int to; int step; };
#define range(...) range((struct range){.from=1,.to=10,.step=1, __VA_ARGS__})   

/* use parentheses to avoid macro subst */             
void (range)(struct range r) {                                                     
    for (int i = r.from; i <= r.to; i += r.step)                                 
        printf("%d ", i);                                                        
    puts("");                                                                    
}                                                                                

int main() {                                                                     
    range();                                                                    
    range(.from=2, .to=4);                                                      
    range(.step=2);                                                             
}    

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

প্রোগ্রাম আউটপুট:

1 2 3 4 5 6 7 8 9 10 
2 3 4 
1 3 5 7 9

2
এটি উইম টেন ব্রিংক বা বিকে সমাধানের চেয়ে সহজ এবং আরও সোজা ফরওয়ার্ড বাস্তবায়ন বলে মনে হচ্ছে। এই বাস্তবায়নের কি কোনও ডাউনসাইড রয়েছে যা অন্যরাও ধারণ করে না?
স্টেফেন্ম 21

24

ওপেনসিভি এর মতো কিছু ব্যবহার করে:

/* in the header file */

#ifdef __cplusplus
    /* in case the compiler is a C++ compiler */
    #define DEFAULT_VALUE(value) = value
#else
    /* otherwise, C compiler, do nothing */
    #define DEFAULT_VALUE(value)
#endif

void window_set_size(unsigned int width  DEFAULT_VALUE(640),
                     unsigned int height DEFAULT_VALUE(400));

ব্যবহারকারী কী লিখতে হবে তা যদি না জানেন তবে এই কৌশলটি সহায়ক হতে পারে:

ব্যবহার উদাহরণ


19

না।

এমনকি খুব সাম্প্রতিক সি 99 স্ট্যান্ডার্ড এটি সমর্থন করে না।


একটি সাধারণ
কোনটি

21
@ কেভিন্ডিম: এটি সম্ভব নয়, এসও উত্তরের ন্যূনতম দৈর্ঘ্যের আদেশ দেয়। আমি চেষ্টা করেছিলাম. :)
বিনোদন

2
আমার উত্তর দেখুন। :)
বিশৃঙ্খলা


14

সংক্ষিপ্ত উত্তর: না

সামান্য দীর্ঘতর উত্তর: একটি পুরানো, পুরানো কাজ রয়েছে যেখানে আপনি একটি স্ট্রিং পাস করেন যা আপনি al চ্ছিক যুক্তিগুলির জন্য পার্স করেন :

int f(int arg1, double arg2, char* name, char *opt);

যেখানে অপ্টটিতে "নাম = মান" জুটি বা কিছু অন্তর্ভুক্ত থাকতে পারে এবং যা আপনি পছন্দ করেন would

n = f(2,3.0,"foo","plot=yes save=no");

স্পষ্টতই এটি কেবল মাঝে মাঝে দরকারী। সাধারণত যখন আপনি কার্যকারিতা পরিবারের একটি একক ইন্টারফেস চান।


আপনি এখনও এমন কণা পদার্থবিজ্ঞানের কোডগুলিতে খুঁজে পান যা পেশাদার প্রোগ্রামগুলি সি ++ (উদাহরণস্বরূপ মূলের মতো ) এ লেখা হয়। এটির প্রধান সুবিধা হ'ল পিছনে সামঞ্জস্যতা বজায় রেখে প্রায় অনির্দিষ্টকালের জন্য এটি বাড়ানো যেতে পারে।


2
এটি ভারার্গসের সাথে একত্রিত করুন এবং আপনি সমস্ত ধরণের মজা পেয়েছেন!
ডেভিড থর্নলে

5
আমি একটি কাস্টম ব্যবহার করব structএবং কলারকে এটি তৈরি করতে, বিভিন্ন বিকল্পের জন্য ক্ষেত্রগুলি পূরণ করতে এবং তারপরে এটিকে ঠিকানা দিয়ে বা NULLডিফল্ট বিকল্পগুলির জন্য পাস করতে চাই।
ক্রিস লুটজ

রুট থেকে কোড নিদর্শন অনুলিপি করা একটি ভয়ানক ধারণা!
নির্বিচারে

13

সম্ভবত এটি করার সর্বোত্তম উপায় (যা আপনার অবস্থার উপর নির্ভর করে আপনার ক্ষেত্রে সম্ভব হতে পারে বা নাও হতে পারে) হ'ল সি ++ এ চলে যাওয়া এবং এটি 'আরও ভাল সি' হিসাবে ব্যবহার করা। আপনি ক্লাস, টেম্পলেট, অপারেটর ওভারলোডিং বা অন্যান্য উন্নত বৈশিষ্ট্যগুলি ব্যবহার না করে সি ++ ব্যবহার করতে পারেন।

এটি আপনাকে ফাংশন ওভারলোডিং এবং ডিফল্ট প্যারামিটারগুলি (এবং আপনি যে কোনও বৈশিষ্ট্যই ব্যবহার করতে পছন্দ করেছেন) দিয়ে সি এর একটি বৈকল্পিক দেবে। আপনি যদি কেবলমাত্র C ++ এর একটি সীমাবদ্ধ উপসেট ব্যবহার করতে সত্যিই গুরুতর হন তবে আপনাকে একটু শৃঙ্খলাবদ্ধ হতে হবে।

প্রচুর লোকেরা বলবেন যে এইভাবে সি ++ ব্যবহার করা ভয়ানক ধারণা এবং তাদের কোনও বক্তব্য থাকতে পারে। তবে এটি কেবল একটি মতামত; আমি সি ++ এর বৈশিষ্ট্যগুলি ব্যবহার করা বৈধ বলে মনে করি যা আপনি পুরো জিনিসটি কিনে না দিয়ে আরামদায়ক হন। আমি মনে করি সি ++ এর সাফল্যের কারণগুলির একটি উল্লেখযোগ্য অংশটি হ'ল এটি একেবারে প্রথম দিকে একে একে খুব ভয়ংকরভাবে প্রোগ্রামার দ্বারা ব্যবহৃত হয়েছিল।


13

তবুও অন্য একটি বিকল্প ব্যবহার করে struct:

struct func_opts {
  int    arg1;
  char * arg2;
  int    arg3;
};

void func(int arg, struct func_opts *opts)
{
    int arg1 = 0, arg3 = 0;
    char *arg2 = "Default";
    if(opts)
      {
        if(opts->arg1)
            arg1 = opts->arg1;
        if(opts->arg2)
            arg2 = opts->arg2;
        if(opts->arg3)
            arg3 = opts->arg3;
      }
    // do stuff
}

// call with defaults
func(3, NULL);

// also call with defaults
struct func_opts opts = {0};
func(3, &opts);

// set some arguments
opts.arg3 = 3;
opts.arg2 = "Yes";
func(3, &opts);

9

না।


2
কাজটি কি? আমি দেখতে পাচ্ছি যে এটি 20202020হেক্সে রয়েছে তবে আমি কীভাবে এটি টাইপ করব?
Lazer

5

ম্যাক্রো ব্যবহার করে অন্য কৌশল:

#include <stdio.h>

#define func(...) FUNC(__VA_ARGS__, 15, 0)
#define FUNC(a, b, ...) func(a, b)

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

int main(void)
{
    printf("%d\n", func(1));
    printf("%d\n", func(1, 2));
    return 0;
}

যদি কেবল একটি যুক্তি পাস bহয় তবে ডিফল্ট মান (এই ক্ষেত্রে 15) প্রাপ্ত হয়


4

না, তবে আপনি ডিফল্ট আরোগুলি ব্যবহার করে আনুষ্ঠানিকভাবে ফাংশনগুলির একটি সেট (বা ম্যাক্রো) ব্যবহার করার বিষয়টি বিবেচনা করতে পারেন :

// No default args
int foo3(int a, int b, int c)
{
    return ...;
}

// Default 3rd arg
int foo2(int a, int b)
{
    return foo3(a, b, 0);  // default c
}

// Default 2nd and 3rd args
int foo1(int a)
{
    return foo3(a, 1, 0);  // default b and c
}

4

হ্যাঁ, সি 99 এর বৈশিষ্ট্য সহ আপনি এটি করতে পারেন। এটি নতুন ডেটা স্ট্রাকচার বা এটির সংজ্ঞা না দিয়ে এবং রানটাইমে কীভাবে ডাকা হবে তা নির্ধারণ না করে এবং কোনও গণনামূলক ওভারহেড ছাড়াই কাজ করে।

বিস্তারিত ব্যাখ্যার জন্য আমার পোস্টটি দেখুন

http://gustedt.wordpress.com/2010/06/03/default-arguments-for-c99/

জেনস


আপনার উত্তর থেকে প্রাপ্ত আমার উত্তরটিও দেখুন ।
শেলবি মুর তৃতীয়

1
একটি উদাহরণ ইনলাইন করুন।
ব্যবহারকারীর 877329

3

সাধারণত না, তবে জিসিসিতে আপনি ম্যাক্রো দিয়ে ফানকাএ () এর শেষ প্যারামিটারটি makeচ্ছিক করতে পারেন।

ফানকবিতে () আমি 'বি' প্যারামিটারের জন্য আমার ডিফল্ট মান প্রয়োজন তা বোঝাতে একটি বিশেষ মান (-1) ব্যবহার করি।

#include <stdio.h> 

int funcA( int a, int b, ... ){ return a+b; }
#define funcA( a, ... ) funcA( a, ##__VA_ARGS__, 8 ) 


int funcB( int a, int b ){
  if( b == -1 ) b = 8;
  return a+b;
}

int main(void){
  printf("funcA(1,2): %i\n", funcA(1,2) );
  printf("funcA(1):   %i\n", funcA(1)   );

  printf("funcB(1, 2): %i\n", funcB(1, 2) );
  printf("funcB(1,-1): %i\n", funcB(1,-1) );
}

1

আমি জেনস গুস্টেটের উত্তরে উন্নতি করেছি যাতে:

  1. ইনলাইন ফাংশন নিয়োগ করা হয় না
  2. প্রিপ্রসেসিংয়ের সময় ডিফল্ট গণনা করা হয়
  3. মডুলার পুনঃব্যবহারযোগ্য ম্যাক্রোগুলি
  4. সংকলক ত্রুটি সেট করা সম্ভব যা অনুমোদিত ডিফল্টগুলির জন্য অপর্যাপ্ত আর্গুমেন্টের ক্ষেত্রে অর্থপূর্ণভাবে মেলে
  5. যদি আর্গুমেন্টের প্রকারগুলি দ্ব্যর্থহীন থাকে তবে ডিফল্টগুলিকে পরামিতি তালিকার লেজ গঠনের প্রয়োজন হয় না
  6. সি 11 _ জেনেরিকের সাথে ইন্টারপ্ট করে
  7. আর্গুমেন্ট সংখ্যা দ্বারা ফাংশন নাম পরিবর্তিত!

variadic.h:

#ifndef VARIADIC

#define _NARG2(_0, _1, _2, ...) _2
#define NUMARG2(...) _NARG2(__VA_ARGS__, 2, 1, 0)
#define _NARG3(_0, _1, _2, _3, ...) _3
#define NUMARG3(...) _NARG3(__VA_ARGS__, 3, 2, 1, 0)
#define _NARG4(_0, _1, _2, _3, _4, ...) _4
#define NUMARG4(...) _NARG4(__VA_ARGS__, 4, 3, 2, 1, 0)
#define _NARG5(_0, _1, _2, _3, _4, _5, ...) _5
#define NUMARG5(...) _NARG5(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define _NARG6(_0, _1, _2, _3, _4, _5, _6, ...) _6
#define NUMARG6(...) _NARG6(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0)
#define _NARG7(_0, _1, _2, _3, _4, _5, _6, _7, ...) _7
#define NUMARG7(...) _NARG7(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
#define _NARG8(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) _8
#define NUMARG8(...) _NARG8(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define _NARG9(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
#define NUMARG9(...) _NARG9(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define __VARIADIC(name, num_args, ...) name ## _ ## num_args (__VA_ARGS__)
#define _VARIADIC(name, num_args, ...) name (__VARIADIC(name, num_args, __VA_ARGS__))
#define VARIADIC(name, num_args, ...) _VARIADIC(name, num_args, __VA_ARGS__)
#define VARIADIC2(name, num_args, ...) __VARIADIC(name, num_args, __VA_ARGS__)

// Vary function name by number of arguments supplied
#define VARIADIC_NAME(name, num_args) name ## _ ## num_args ## _name ()
#define NVARIADIC(name, num_args, ...) _VARIADIC(VARIADIC_NAME(name, num_args), num_args, __VA_ARGS__)

#endif

সরলীকৃত ব্যবহারের দৃশ্য:

const uint32*
uint32_frombytes(uint32* out, const uint8* in, size_t bytes);

/*
The output buffer defaults to NULL if not provided.
*/

#include "variadic.h"

#define uint32_frombytes_2(   b, c) NULL, b, c
#define uint32_frombytes_3(a, b, c)    a, b, c
#define uint32_frombytes(...) VARIADIC(uint32_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

এবং _ জেনারিক সহ:

const uint8*
uint16_tobytes(const uint16* in, uint8* out, size_t bytes);

const uint16*
uint16_frombytes(uint16* out, const uint8* in, size_t bytes);

const uint8*
uint32_tobytes(const uint32* in, uint8* out, size_t bytes);

const uint32*
uint32_frombytes(uint32* out, const uint8* in, size_t bytes);

/*
The output buffer defaults to NULL if not provided.
Generic function name supported on the non-uint8 type, except where said type
is unavailable because the argument for output buffer was not provided.
*/

#include "variadic.h"

#define   uint16_tobytes_2(a,    c) a, NULL, c
#define   uint16_tobytes_3(a, b, c) a,    b, c
#define   uint16_tobytes(...) VARIADIC(  uint16_tobytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

#define uint16_frombytes_2(   b, c) NULL, b, c
#define uint16_frombytes_3(a, b, c)    a, b, c
#define uint16_frombytes(...) VARIADIC(uint16_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

#define   uint32_tobytes_2(a,    c) a, NULL, c
#define   uint32_tobytes_3(a, b, c) a,    b, c
#define   uint32_tobytes(...) VARIADIC(  uint32_tobytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

#define uint32_frombytes_2(   b, c) NULL, b, c
#define uint32_frombytes_3(a, b, c)    a, b, c
#define uint32_frombytes(...) VARIADIC(uint32_frombytes, NUMARG3(__VA_ARGS__), __VA_ARGS__)

#define   tobytes(a, ...) _Generic((a),                                                                                                 \
                                   const uint16*: uint16_tobytes,                                                                       \
                                   const uint32*: uint32_tobytes)  (VARIADIC2(  uint32_tobytes, NUMARG3(a, __VA_ARGS__), a, __VA_ARGS__))

#define frombytes(a, ...) _Generic((a),                                                                                                 \
                                         uint16*: uint16_frombytes,                                                                     \
                                         uint32*: uint32_frombytes)(VARIADIC2(uint32_frombytes, NUMARG3(a, __VA_ARGS__), a, __VA_ARGS__))

এবং বৈকল্পিক ফাংশন নাম নির্বাচনের সাথে, যা _ জেনেরিকের সাথে একত্রিত করা যায় না:

// winternitz() with 5 arguments is replaced with merkle_lamport() on those 5 arguments.

#define   merkle_lamport_5(a, b, c, d, e) a, b, c, d, e
#define   winternitz_7(a, b, c, d, e, f, g) a, b, c, d, e, f, g
#define   winternitz_5_name() merkle_lamport
#define   winternitz_7_name() winternitz
#define   winternitz(...) NVARIADIC(winternitz, NUMARG7(__VA_ARGS__), __VA_ARGS__)

1

হ্যাঁ

ম্যাক্রোর মাধ্যমে

3 পরামিতি:

#define my_func2(...) my_func3(__VA_ARGS__, 0.5)
#define my_func1(...) my_func2(__VA_ARGS__, 10)
#define VAR_FUNC(_1, _2, _3, NAME, ...) NAME
#define my_func(...) VAR_FUNC(__VA_ARGS__, my_func3, my_func2, my_func1)(__VA_ARGS__)

void my_func3(char a, int b, float c) // b=10, c=0.5
{
    printf("a=%c; b=%d; c=%f\n", a, b, c);
}

আপনি যদি চতুর্থ যুক্তি চান তবে একটি অতিরিক্ত my_func3 যুক্ত করা দরকার। VAR_FUNC, my_func2 এবং my_func এর পরিবর্তনগুলি লক্ষ্য করুন

4 পরামিতি:

#define my_func3(...) my_func4(__VA_ARGS__, "default") // <== New function added
#define my_func2(...) my_func3(__VA_ARGS__, (float)1/2)
#define my_func1(...) my_func2(__VA_ARGS__, 10)
#define VAR_FUNC(_1, _2, _3, _4, NAME, ...) NAME
#define my_func(...) VAR_FUNC(__VA_ARGS__, my_func4, my_func3, my_func2, my_func1)(__VA_ARGS__)

void my_func4(char a, int b, float c, const char* d) // b=10, c=0.5, d="default"
{
    printf("a=%c; b=%d; c=%f; d=%s\n", a, b, c, d);
}

কেবলমাত্র ব্যতিক্রম যে ফ্লোট ভেরিয়েবলগুলিকে ডিফল্ট মান দেওয়া যায় না ( যদি না এটি 3 টি প্যারামিটারের ক্ষেত্রে যেমন শেষ যুক্তি হিসাবে থাকে ), কারণ তাদের সময়কালের ('।') প্রয়োজন হয়, যা ম্যাক্রো আর্গুমেন্টের মধ্যে গৃহীত হয় না। তবে my_func2 ম্যাক্রো ( 4 টি প্যারামিটার ক্ষেত্রে) হিসাবে দেখা হিসাবে প্রায় একটি কাজ সনাক্ত করতে পারেন )

কার্যক্রম

int main(void)
{
    my_func('a');
    my_func('b', 20);
    my_func('c', 200, 10.5);
    my_func('d', 2000, 100.5, "hello");

    return 0;
}

আউটপুট:

a=a; b=10; c=0.500000; d=default                                                                                                                                                  
a=b; b=20; c=0.500000; d=default                                                                                                                                                  
a=c; b=200; c=10.500000; d=default                                                                                                                                                
a=d; b=2000; c=100.500000; d=hello  

0

হ্যাঁ আপনি সামম্যুলার কিছু করতে পারেন, এখানে আপনি পেতে পারেন বিভিন্ন যুক্তি তালিকাগুলি জানতে হবে তবে সবগুলি পরিচালনা করার জন্য আপনার একই ফাংশন রয়েছে।

typedef enum { my_input_set1 = 0, my_input_set2, my_input_set3} INPUT_SET;

typedef struct{
    INPUT_SET type;
    char* text;
} input_set1;

typedef struct{
    INPUT_SET type;
    char* text;
    int var;
} input_set2;

typedef struct{
    INPUT_SET type;
    int text;
} input_set3;

typedef union
{
    INPUT_SET type;
    input_set1 set1;
    input_set2 set2;
    input_set3 set3;
} MY_INPUT;

void my_func(MY_INPUT input)
{
    switch(input.type)
    {
        case my_input_set1:
        break;
        case my_input_set2:
        break;
        case my_input_set3:
        break;
        default:
        // unknown input
        break;
    }
}

-6

আমরা কেন এটি করতে পারি না।

Alচ্ছিক যুক্তিটিকে একটি ডিফল্ট মান দিন। এইভাবে, ফাংশন কলকারী অগত্যা আর্গুমেন্টের মান পাস করার প্রয়োজন হয় না। যুক্তি ডিফল্ট মান নেয়। এবং সহজেই সেই যুক্তি ক্লায়েন্টের জন্য alচ্ছিক হয়ে যায়।

যেমন যেমন

অকার্যকর foo (int a, int b = 0);

এখানে খ একটি alচ্ছিক যুক্তি।


10
অত্যাশ্চর্য অন্তর্দৃষ্টি, সমস্যাটি হ'ল সি optionচ্ছিক যুক্তি বা অতিরিক্ত লোড ফাংশনগুলিকে সমর্থন করে না, সুতরাং সরাসরি সমাধান সংকলন করে না।
থমাস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.