C में फ़ंक्शन ओवरलोडिंग कैसे प्राप्त करें?


240

क्या सी में फ़ंक्शन ओवरलोडिंग प्राप्त करने का कोई तरीका है? मैं साधारण कार्यों को देख रहा हूँ जैसे अतिभारित होना

foo (int a)  
foo (char b)  
foo (float c , int d)

मुझे लगता है कि आगे कोई सीधा रास्ता नहीं है; मैं वर्कअराउंड की तलाश कर रहा हूं यदि कोई मौजूद है।


6
तुमने ऐसा क्यों करना चाहोगे? C की कोई बहुरूपी क्षमता नहीं है। तो फू (यादृच्छिक प्रकार) असंभव है। बस असली funcs foo_i, foo_ch, foo_d, आदि
बनाते हैं

4
आप शून्य पॉइंटर्स और टाइप आईडी का उपयोग करके बुराई पर जा सकते हैं।
alk

11
मुझे लगता है कि मुझे इस तथ्य पर ध्यान आकर्षित करना चाहिए कि इस प्रश्न का उत्तर बदल गया है क्योंकि यह मूल रूप से पूछा गया था , नए सी मानक के साथ।
लेउशेंको सेप

जवाबों:


127

कुछ संभावनाएं हैं:

  1. प्रिंटफ़ शैली कार्य (एक तर्क के रूप में टाइप करें)
  2. opengl स्टाइल फ़ंक्शंस (प्रकार फ़ंक्शन नाम)
  3. c ++ का सबसेट (यदि आप c ++ कंपाइलर का उपयोग कर सकते हैं)

1
क्या आप ओपेंगल शैली के कार्यों के लिए लिंक समझा सकते हैं या प्रदान कर सकते हैं?
FL4SOF

1
@ लेज़र: यहाँ एक सरल प्रिंटफ जैसे फ़ंक्शन कार्यान्वयन है।
अलेक्सई फ्रुंज़े

12
नहीं। प्रिंटफ फ़ंक्शन ओवरलोडिंग नहीं है। यह vararg का उपयोग करता है !!! और C फंक्शन ओवरलोडिंग का समर्थन नहीं करता है।
जक

52
@hqt उत्तर कभी ओवरलोडिंग शब्द का उल्लेख नहीं करता है।
क्रियास

1
@kyrias यदि इसका जवाब गलत सवाल के बारे में नहीं है तो यह गलत है
माइकल मूरजेक

233

हाँ!

चूंकि यह प्रश्न पूछा गया था , इसलिए C11 में कीवर्ड को जोड़ने के लिए मानक C (कोई एक्सटेंशन) ने फ़ंक्शन ओवरलोडिंग (ऑपरेटर नहीं) के लिए प्रभावी रूप से समर्थन प्राप्त किया है _Generic। (संस्करण 4.9 के बाद से GCC में समर्थित)

(ओवरलोडिंग वास्तव में फैशन में दिखाए गए "बिल्ट-इन" नहीं है, लेकिन यह उस तरह से काम करने वाले कुछ को लागू करने के लिए आसान है।)

_Genericके रूप में एक ही परिवार में एक संकलन समय ऑपरेटर है sizeofऔर _Alignof। यह मानक खंड 6.5.1.1 में वर्णित है। यह दो मुख्य मापदंडों को स्वीकार करता है: एक अभिव्यक्ति (जो रनटाइम पर मूल्यांकन नहीं की जाएगी), और एक प्रकार / अभिव्यक्ति एसोसिएशन सूची जो एक switchब्लॉक की तरह लगती है । _Genericअभिव्यक्ति के समग्र प्रकार को प्राप्त करता है और फिर उसके प्रकार के लिए सूची में अंतिम परिणाम अभिव्यक्ति का चयन करने के लिए उस पर "स्विच" करता है:

_Generic(1, float: 2.0,
            char *: "2",
            int: 2,
            default: get_two_object());

उपरोक्त अभिव्यक्ति का मूल्यांकन है 2- नियंत्रण अभिव्यक्ति का प्रकार है int, इसलिए यह intमूल्य के साथ जुड़े अभिव्यक्ति को चुनता है । इसमें से कुछ भी रनटाइम पर नहीं रहता है। ( defaultक्लॉज वैकल्पिक है: यदि आप इसे छोड़ देते हैं और प्रकार मेल नहीं खाता है, तो यह संकलन त्रुटि का कारण होगा।)

जिस तरह से यह फ़ंक्शन ओवरलोडिंग के लिए उपयोगी है वह यह है कि इसे सी प्रीप्रोसेसर द्वारा डाला जा सकता है और कंट्रोलिंग मैक्रो को दिए गए तर्कों के प्रकार के आधार पर एक परिणाम अभिव्यक्ति चुन सकता है। तो (सी मानक से उदाहरण):

#define cbrt(X) _Generic((X),                \
                         long double: cbrtl, \
                         default: cbrt,      \
                         float: cbrtf        \
                         )(X)

यह मैक्रो ओवरलोड cbrtऑपरेशन को लागू करता है, मैक्रो को तर्क के प्रकार पर भेजकर, एक उपयुक्त कार्यान्वयन फ़ंक्शन का चयन करता है, और फिर उस फ़ंक्शन के मूल मैक्रो तर्क को पास करता है।

तो अपने मूल उदाहरण को लागू करने के लिए, हम यह कर सकते हैं:

foo_int (int a)  
foo_char (char b)  
foo_float_int (float c , int d)

#define foo(_1, ...) _Generic((_1),                                  \
                              int: foo_int,                          \
                              char: foo_char,                        \
                              float: _Generic((FIRST(__VA_ARGS__,)), \
                                     int: foo_float_int))(_1, __VA_ARGS__)
#define FIRST(A, ...) A

इस मामले में हम default:तीसरे मामले के लिए एक संघ का उपयोग कर सकते थे , लेकिन यह प्रदर्शित नहीं करता है कि सिद्धांत को कई तर्कों तक कैसे बढ़ाया जाए। अंतिम परिणाम यह है कि आप foo(...)अपने कोड में अपने तर्कों के प्रकार के बारे में चिंता किए बिना (बहुत [1]) उपयोग कर सकते हैं ।


अधिक जटिल स्थितियों के लिए, उदाहरण के लिए, बड़ी संख्या में तर्कों, या अलग-अलग संख्याओं को ओवरलोड करने के लिए, आप स्थैतिक प्रेषण संरचनाओं को स्वचालित रूप से उत्पन्न करने के लिए उपयोगिता मैक्रो का उपयोग कर सकते हैं:

void print_ii(int a, int b) { printf("int, int\n"); }
void print_di(double a, int b) { printf("double, int\n"); }
void print_iii(int a, int b, int c) { printf("int, int, int\n"); }
void print_default(void) { printf("unknown arguments\n"); }

#define print(...) OVERLOAD(print, (__VA_ARGS__), \
    (print_ii, (int, int)), \
    (print_di, (double, int)), \
    (print_iii, (int, int, int)) \
)

#define OVERLOAD_ARG_TYPES (int, double)
#define OVERLOAD_FUNCTIONS (print)
#include "activate-overloads.h"

int main(void) {
    print(44, 47);   // prints "int, int"
    print(4.4, 47);  // prints "double, int"
    print(1, 2, 3);  // prints "int, int, int"
    print("");       // prints "unknown arguments"
}

( यहाँ कार्यान्वयन ) तो कुछ प्रयासों के साथ, आप बॉयलरप्लेट की मात्रा को कम करने के लिए ओवरलोडिंग के लिए देशी समर्थन के साथ एक भाषा की तरह बहुत कम देख सकते हैं।

एक तरफ के रूप में, C99 में तर्कों (प्रकार नहीं) की संख्या पर ओवरलोड करना पहले से ही संभव था


[१] ध्यान दें कि सी जिस तरह से मूल्यांकन करता है वह आपको यात्रा कर सकता है। foo_intउदाहरण के लिए, यदि आप इसे वर्ण शाब्दिक रूप से पारित करने का प्रयास करते हैं, तो यह चुनेंगे , और अगर आप चाहते हैं कि आपको अपने ओवरलोड को स्ट्रिंग शाब्दिकों का समर्थन करने के लिए थोड़ा गड़बड़ करना पड़े। हालांकि कुल मिलाकर बहुत अच्छा है।


आपके उदाहरण के आधार पर ऐसा लगता है कि केवल अतिभारित वस्तु मैक्रोज़ की तरह कार्य कर रही है। मुझे यह देखने दें कि क्या मैं सही तरीके से समझता हूं: यदि आप उन कार्यों को ओवरलोड करना चाहते हैं, जो आप अभी-अभी पारित किए गए डेटा प्रकारों के आधार पर फ़ंक्शन कॉल को हटाने के लिए प्रीप्रोसेसर का उपयोग कर रहे हैं, है ना?
निक

काश, जब भी C11 मुझे लगता है पर पकड़ना शुरू करता है, तो MISRA ने उन्हीं कारणों से इस सुविधा को ग्रहण नहीं किया, जब तक कि वे चर तर्कों की सूची को रोक नहीं देते। मैं अपनी दुनिया में MISRA द्वारा बहुत करीब से छड़ी करने की कोशिश करता हूं।
निक

9
@ यह सब ओवरलोडिंग है। यह केवल अन्य भाषाओं में निहित है (उदाहरण के लिए, आप किसी भी भाषा में "एक ओवरलोड फ़ंक्शन के लिए एक पॉइंटर को वास्तव में प्राप्त नहीं कर सकते हैं", क्योंकि ओवरलोडिंग का अर्थ कई निकायों से है)। ध्यान दें कि यह प्रीप्रोसेसर द्वारा अकेले नहीं किया जा सकता है, इसके लिए किसी प्रकार के प्रेषण की आवश्यकता होती है; प्रीप्रोसेसर सिर्फ यह कैसे दिखता है बदल जाता है।
लेहशेंको

1
जैसा कि कोई है जो C99 से काफी परिचित है और सीखना चाहता है कि यह कैसे करना है, यह अत्यधिक जटिल लगता है, यहां तक ​​कि सी के लिए भी
Tyler Crompton

5
@ टायलर क्रॉम्पटन का संकलन समय पर मूल्यांकन किया जाता है।
JAB

75

जैसा कि पहले ही कहा गया है, इस अर्थ में ओवरलोडिंग का मतलब है कि सी द्वारा समर्थित नहीं है। समस्या को हल करने के लिए एक सामान्य मुहावरा फ़ंक्शन को टैग किए गए यूनियन को स्वीकार करने की अनुमति देता है । यह एक structपैरामीटर द्वारा कार्यान्वित किया जाता है , जहां structस्वयं में कुछ प्रकार के संकेतक होते हैं, जैसे कि enumए, और unionविभिन्न प्रकार के मान। उदाहरण:

#include <stdio.h>

typedef enum {
    T_INT,
    T_FLOAT,
    T_CHAR,
} my_type;

typedef struct {
    my_type type;
    union {
        int a; 
        float b; 
        char c;
    } my_union;
} my_struct;

void set_overload (my_struct *whatever) 
{
    switch (whatever->type) 
    {
        case T_INT:
            whatever->my_union.a = 1;
            break;
        case T_FLOAT:
            whatever->my_union.b = 2.0;
            break;
        case T_CHAR:
            whatever->my_union.c = '3';
    }
}

void printf_overload (my_struct *whatever) {
    switch (whatever->type) 
    {
        case T_INT:
            printf("%d\n", whatever->my_union.a);
            break;
        case T_FLOAT:
            printf("%f\n", whatever->my_union.b);
            break;
        case T_CHAR:
            printf("%c\n", whatever->my_union.c);
            break;
    }

}

int main (int argc, char* argv[])
{
    my_struct s;

    s.type=T_INT;
    set_overload(&s);
    printf_overload(&s);

    s.type=T_FLOAT;
    set_overload(&s);
    printf_overload(&s);

    s.type=T_CHAR;
    set_overload(&s);
    printf_overload(&s); 
}

22
आप क्यों नहीं बस सब नहीं होगा whateverरों अलग कार्यों में ( set_int, set_float, आदि)। फिर "टाइप के साथ टैगिंग" हो जाता है "फ़ंक्शन नाम में टाइप नाम जोड़ें"। इस उत्तर में संस्करण में अधिक टाइपिंग, अधिक रनटाइम लागत, त्रुटियों का अधिक मौका शामिल है जो संकलन समय पर नहीं पकड़े जाएंगे ... मैं इस तरह से काम करने में बिल्कुल भी कोई फायदा नहीं देख सकता ! 16 upvotes ?!
बेन

20
बेन, यह जवाब उत्तपन्न है क्योंकि यह प्रश्न का उत्तर देता है, केवल "ऐसा मत करो" कहने के बजाय। आप सही हैं कि अलग-अलग कार्यों का उपयोग करने के लिए सी में यह अधिक मुहावरेदार है, लेकिन अगर कोई सी में बहुरूपता चाहता है, तो यह इसे करने का एक अच्छा तरीका है। इसके अलावा, यह उत्तर दिखाता है कि आप संकलक या वीएम में रन-टाइम बहुरूपता को कैसे लागू करेंगे: एक प्रकार के साथ मूल्य को टैग करें, और फिर उसके आधार पर प्रेषण करें। इस प्रकार यह मूल प्रश्न का एक उत्कृष्ट उत्तर है।
निल्स वॉन बर्थ

20

यहाँ स्पष्ट और सबसे संक्षिप्त उदाहरण है जो मैंने C में कार्यभार को प्रदर्शित करते हुए पाया है:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

char *adds(char *a, char *b) {
    char *res = malloc(strlen(a) + strlen(b) + 1);
    strcpy(res, a);
    strcat(res, b);
    return res;
}

#define add(a, b) _Generic(a, int: addi, char*: adds)(a, b)

int main(void) {
    int a = 1, b = 2;
    printf("%d\n", add(a, b)); // 3

    char *c = "hello ", *d = "world";
    printf("%s\n", add(c, d)); // hello world

    return 0;
}

https://gist.github.com/barosl/e0af4a92b2b8cabd05a7


1
मुझे लगता है कि यह भावना (लेकिन कम स्पष्टीकरण के साथ) में stackoverflow.com/a/25026358/1240268 का एक प्रकार है ।
एंडी हेडन

1
मैं निश्चित रूप से स्लाइसिंग और डिपिंग चॉप के लिए पूर्ण और रन करने योग्य कोड का 1 एकल निरंतर ब्लॉक पसंद करता हूं जो कि # 1240268 है। प्रत्येक अपने स्वयं के लिए।
जे टेलर टेलर

1
मुझे ऐसे उत्तर पसंद हैं जो बताते हैं कि वे क्या कर रहे हैं और वे क्यों काम करते हैं। यह न तो करता है। "सर्वश्रेष्ठ मैंने अभी तक देखा है:" प्रदर्शनी नहीं है।
अंडरस्कोर_ड

19

यदि आपका कंपाइलर gcc है और आप हर बार जब आप एक नया अधिभार जोड़ते हैं तो हाथ अपडेट करने में कोई आपत्ति नहीं है। आप मैक्रो मैजिक कर सकते हैं और आपको कॉलर्स के संदर्भ में जो परिणाम चाहिए, वह लिखना अच्छा नहीं है ... लेकिन यह संभव है

__builtin_types_compatible_p को देखें, फिर एक मैक्रो को परिभाषित करने के लिए इसका उपयोग करें जो कुछ ऐसा करता है

#define foo(a) \
((__builtin_types_compatible_p(int, a)?foo(a):(__builtin_types_compatible_p(float, a)?foo(a):)

लेकिन हाँ बुरा, बस नहीं

संपादित करें: C1X को इस प्रकार दिखने वाले सामान्य भावों के लिए समर्थन मिल रहा है:

#define cbrt(X) _Generic((X), long double: cbrtl, \
                              default: cbrt, \
                              float: cbrtf)(X)

13

हाँ, की तरह।

यहाँ आप उदाहरण के लिए जाते हैं:

void printA(int a){
printf("Hello world from printA : %d\n",a);
}

void printB(const char *buff){
printf("Hello world from printB : %s\n",buff);
}

#define Max_ITEMS() 6, 5, 4, 3, 2, 1, 0 
#define __VA_ARG_N(_1, _2, _3, _4, _5, _6, N, ...) N
#define _Num_ARGS_(...) __VA_ARG_N(__VA_ARGS__) 
#define NUM_ARGS(...) (_Num_ARGS_(_0, ## __VA_ARGS__, Max_ITEMS()) - 1) 
#define CHECK_ARGS_MAX_LIMIT(t) if(NUM_ARGS(args)>t)
#define CHECK_ARGS_MIN_LIMIT(t) if(NUM_ARGS(args) 
#define print(x , args ...) \
CHECK_ARGS_MIN_LIMIT(1) printf("error");fflush(stdout); \
CHECK_ARGS_MAX_LIMIT(4) printf("error");fflush(stdout); \
({ \
if (__builtin_types_compatible_p (typeof (x), int)) \
printA(x, ##args); \
else \
printB (x,##args); \
})

int main(int argc, char** argv) {
    int a=0;
    print(a);
    print("hello");
    return (EXIT_SUCCESS);
}

यह उत्पादन करेगा 0 और हैलो .. प्रिंटए और प्रिंटबी से।


2
int main (int argc, char ** argv) {int a = 0; प्रिंट (क); प्रिंट ( "हैलो"); वापसी (EXIT_SUCCESS); } आउटपुट 0 और हैलो .. प्रिंटए और प्रिंटबी से ...
कैप्टन बारबोसा

1
__builtin_types_compatible_p, क्या GCC संकलक विशिष्ट नहीं है?
सोगार्टार

11

निम्नलिखित दृष्टिकोण a2800276 के समान है , लेकिन कुछ C99 मैक्रो जादू के साथ जोड़ा गया है:

// we need `size_t`
#include <stddef.h>

// argument types to accept
enum sum_arg_types { SUM_LONG, SUM_ULONG, SUM_DOUBLE };

// a structure to hold an argument
struct sum_arg
{
    enum sum_arg_types type;
    union
    {
        long as_long;
        unsigned long as_ulong;
        double as_double;
    } value;
};

// determine an array's size
#define count(ARRAY) ((sizeof (ARRAY))/(sizeof *(ARRAY)))

// this is how our function will be called
#define sum(...) _sum(count(sum_args(__VA_ARGS__)), sum_args(__VA_ARGS__))

// create an array of `struct sum_arg`
#define sum_args(...) ((struct sum_arg []){ __VA_ARGS__ })

// create initializers for the arguments
#define sum_long(VALUE) { SUM_LONG, { .as_long = (VALUE) } }
#define sum_ulong(VALUE) { SUM_ULONG, { .as_ulong = (VALUE) } }
#define sum_double(VALUE) { SUM_DOUBLE, { .as_double = (VALUE) } }

// our polymorphic function
long double _sum(size_t count, struct sum_arg * args)
{
    long double value = 0;

    for(size_t i = 0; i < count; ++i)
    {
        switch(args[i].type)
        {
            case SUM_LONG:
            value += args[i].value.as_long;
            break;

            case SUM_ULONG:
            value += args[i].value.as_ulong;
            break;

            case SUM_DOUBLE:
            value += args[i].value.as_double;
            break;
        }
    }

    return value;
}

// let's see if it works

#include <stdio.h>

int main()
{
    unsigned long foo = -1;
    long double value = sum(sum_long(42), sum_ulong(foo), sum_double(1e10));
    printf("%Le\n", value);
    return 0;
}

11

यह बिल्कुल भी मदद नहीं कर सकता है, लेकिन यदि आप क्लैंग का उपयोग कर रहे हैं तो आप अधिभार विशेषता का उपयोग कर सकते हैं - यह सी के रूप में संकलन करते समय भी काम करता है

http://clang.llvm.org/docs/AttributeReference.html#overloadable

हैडर

extern void DecodeImageNow(CGImageRef image, CGContextRef usingContext) __attribute__((overloadable));
extern void DecodeImageNow(CGImageRef image) __attribute__((overloadable));

कार्यान्वयन

void __attribute__((overloadable)) DecodeImageNow(CGImageRef image, CGContextRef usingContext { ... }
void __attribute__((overloadable)) DecodeImageNow(CGImageRef image) { ... }

10

इस अर्थ में आपका मतलब है - नहीं, आप नहीं कर सकते।

आप एक va_argसमारोह की तरह की घोषणा कर सकते हैं

void my_func(char* format, ...);

, लेकिन आपको पहले तर्क में वेरिएबल्स की संख्या और उनके प्रकारों के बारे में कुछ प्रकार की जानकारी पास करनी होगी - जैसे printf()कि।


6

आम तौर पर यह इंगित करने के लिए एक मस्सा है कि नाम के साथ जोड़ा या पूर्वनिर्मित है। आप मैक्रोज़ के साथ दूर हो सकते हैं कुछ उदाहरण हैं, लेकिन यह निर्भर करता है कि आप क्या करने की कोशिश कर रहे हैं। सी में कोई बहुरूपता नहीं है, केवल जबरदस्ती है।

मैक्रो के साथ सरल सामान्य ऑपरेशन किए जा सकते हैं:

#define max(x,y) ((x)>(y)?(x):(y))

यदि आपका कंपाइलर टाइपोफ़ का समर्थन करता है , तो अधिक जटिल संचालन को मैक्रो में रखा जा सकता है। फिर आप एक ही ऑपरेशन के विभिन्न प्रकारों का समर्थन करने के लिए प्रतीक फू (x) रख सकते हैं, लेकिन आप अलग-अलग अधिभार के बीच के व्यवहार को अलग नहीं कर सकते। यदि आप मैक्रोज़ के बजाय वास्तविक कार्य चाहते हैं, तो आप नाम टाइप करने में सक्षम हो सकते हैं और इसे एक्सेस करने के लिए दूसरी पेस्टिंग का उपयोग कर सकते हैं (मैंने कोशिश नहीं की है)।


क्या आप मैक्रो आधारित दृष्टिकोण पर थोड़ा अधिक बता सकते हैं।
FL4SOF

4

लेशेंको का जवाब वास्तव में अच्छा है - पूरी तरह से: fooउदाहरण जीसीसी के साथ संकलित नहीं करता है, जो कि विफल रहता है foo(7), FIRSTमैक्रो और वास्तविक फ़ंक्शन कॉल पर ठोकर खा रहा है (और (_1, __VA_ARGS__), एक अधिशेष अल्पविराम के साथ शेष है। इसके अतिरिक्त, हम मुसीबत में हैं अगर हम अतिरिक्त अधिभार प्रदान करना चाहते हैं। , जैसे foo(double)

इसलिए मैंने उत्तर को थोड़ा और विस्तृत करने का फैसला किया, जिसमें एक शून्य अधिभार की अनुमति देना भी शामिल है ( foo(void)- जिससे काफी परेशानी हुई ...)।

आइडिया अब है: विभिन्न मैक्रो में एक से अधिक जेनेरिक को परिभाषित करें और तर्कों की संख्या के अनुसार सही एक का चयन करें!

इस उत्तर के आधार पर तर्कों की संख्या काफी आसान है :

#define foo(...) SELECT(__VA_ARGS__)(__VA_ARGS__)

#define SELECT(...) CONCAT(SELECT_, NARG(__VA_ARGS__))(__VA_ARGS__)
#define CONCAT(X, Y) CONCAT_(X, Y)
#define CONCAT_(X, Y) X ## Y

यह अच्छा है, हम SELECT_1या तो या SELECT_2(या अधिक तर्क, यदि आप चाहते हैं / उनकी आवश्यकता है) का समाधान करते हैं, तो हमें बस उचित परिभाषित करने की आवश्यकता है:

#define SELECT_0() foo_void
#define SELECT_1(_1) _Generic ((_1),    \
        int: foo_int,                   \
        char: foo_char,                 \
        double: foo_double              \
)
#define SELECT_2(_1, _2) _Generic((_1), \
        double: _Generic((_2),          \
                int: foo_double_int     \
        )                               \
)

ठीक है, मैंने पहले ही शून्य अधिभार जोड़ दिया है - हालांकि, यह वास्तव में सी मानक द्वारा कवर नहीं किया गया है, जो खाली वैरेडिक तर्कों को अनुमति नहीं देता है, अर्थात हम फिर संकलक एक्सटेंशन पर भरोसा करते हैं !

बहुत पहले, एक खाली मैक्रो कॉल ( foo()) अभी भी एक टोकन का उत्पादन करता है, लेकिन एक खाली। इसलिए मैक्रो मैक्रो वास्तव में खाली मैक्रो कॉल पर भी 0 के बजाय 1 रिटर्न करता है। हम इस समस्या को "आसानी से" समाप्त कर सकते हैं, यदि हम __VA_ARGS__ सशर्त रूप से सूची खाली होने या न होने के आधार पर अल्पविराम लगाते हैं:

#define NARG(...) ARG4_(__VA_ARGS__ COMMA(__VA_ARGS__) 4, 3, 2, 1, 0)

यह आसान लग रहा था , लेकिन COMMAमैक्रो काफी भारी है; सौभाग्य से, विषय पहले से ही जेन्स गुस्तेद (धन्यवाद, जेन्स) के एक ब्लॉग में शामिल है । मूल चाल यह है कि फ़ंक्शन मैक्रोज़ का विस्तार नहीं किया जाता है, यदि कोष्ठक द्वारा पालन नहीं किया जाता है, तो आगे की व्याख्या के लिए, जेन्स के ब्लॉग पर एक नज़र डालें ... हमें केवल मैक्रोज़ को अपनी आवश्यकताओं को थोड़ा संशोधित करना होगा (मैं छोटे नामों का उपयोग करने जा रहा हूं) और संक्षिप्तता के लिए कम तर्क)।

#define ARGN(...) ARGN_(__VA_ARGS__)
#define ARGN_(_0, _1, _2, _3, N, ...) N
#define HAS_COMMA(...) ARGN(__VA_ARGS__, 1, 1, 1, 0)

#define SET_COMMA(...) ,

#define COMMA(...) SELECT_COMMA             \
(                                           \
        HAS_COMMA(__VA_ARGS__),             \
        HAS_COMMA(__VA_ARGS__ ()),          \
        HAS_COMMA(SET_COMMA __VA_ARGS__),   \
        HAS_COMMA(SET_COMMA __VA_ARGS__ ()) \
)

#define SELECT_COMMA(_0, _1, _2, _3) SELECT_COMMA_(_0, _1, _2, _3)
#define SELECT_COMMA_(_0, _1, _2, _3) COMMA_ ## _0 ## _1 ## _2 ## _3

#define COMMA_0000 ,
#define COMMA_0001
#define COMMA_0010 ,
// ... (all others with comma)
#define COMMA_1111 ,

और अब हम ठीक हैं ...

एक ब्लॉक में पूरा कोड:

/*
 * demo.c
 *
 *  Created on: 2017-09-14
 *      Author: sboehler
 */

#include <stdio.h>

void foo_void(void)
{
    puts("void");
}
void foo_int(int c)
{
    printf("int: %d\n", c);
}
void foo_char(char c)
{
    printf("char: %c\n", c);
}
void foo_double(double c)
{
    printf("double: %.2f\n", c);
}
void foo_double_int(double c, int d)
{
    printf("double: %.2f, int: %d\n", c, d);
}

#define foo(...) SELECT(__VA_ARGS__)(__VA_ARGS__)

#define SELECT(...) CONCAT(SELECT_, NARG(__VA_ARGS__))(__VA_ARGS__)
#define CONCAT(X, Y) CONCAT_(X, Y)
#define CONCAT_(X, Y) X ## Y

#define SELECT_0() foo_void
#define SELECT_1(_1) _Generic ((_1), \
        int: foo_int,                \
        char: foo_char,              \
        double: foo_double           \
)
#define SELECT_2(_1, _2) _Generic((_1), \
        double: _Generic((_2),          \
                int: foo_double_int     \
        )                               \
)

#define ARGN(...) ARGN_(__VA_ARGS__)
#define ARGN_(_0, _1, _2, N, ...) N

#define NARG(...) ARGN(__VA_ARGS__ COMMA(__VA_ARGS__) 3, 2, 1, 0)
#define HAS_COMMA(...) ARGN(__VA_ARGS__, 1, 1, 0)

#define SET_COMMA(...) ,

#define COMMA(...) SELECT_COMMA             \
(                                           \
        HAS_COMMA(__VA_ARGS__),             \
        HAS_COMMA(__VA_ARGS__ ()),          \
        HAS_COMMA(SET_COMMA __VA_ARGS__),   \
        HAS_COMMA(SET_COMMA __VA_ARGS__ ()) \
)

#define SELECT_COMMA(_0, _1, _2, _3) SELECT_COMMA_(_0, _1, _2, _3)
#define SELECT_COMMA_(_0, _1, _2, _3) COMMA_ ## _0 ## _1 ## _2 ## _3

#define COMMA_0000 ,
#define COMMA_0001
#define COMMA_0010 ,
#define COMMA_0011 ,
#define COMMA_0100 ,
#define COMMA_0101 ,
#define COMMA_0110 ,
#define COMMA_0111 ,
#define COMMA_1000 ,
#define COMMA_1001 ,
#define COMMA_1010 ,
#define COMMA_1011 ,
#define COMMA_1100 ,
#define COMMA_1101 ,
#define COMMA_1110 ,
#define COMMA_1111 ,

int main(int argc, char** argv)
{
    foo();
    foo(7);
    foo(10.12);
    foo(12.10, 7);
    foo((char)'s');

    return 0;
}

1

क्या आप केवल C ++ का उपयोग नहीं कर सकते हैं और इस को छोड़कर अन्य सभी C ++ सुविधाओं का उपयोग नहीं कर सकते हैं?

यदि अभी भी कोई सख्त सी नहीं है तो मैं इसके बजाय वैरडीकल कार्यों की सिफारिश करूंगा


3
नहीं अगर C ++ कंपाइलर OS के लिए उपलब्ध नहीं है तो वह किसके लिए कोडिंग कर रहा है।
ब्रायन

2
केवल इतना ही नहीं, बल्कि वह ऐसा सी एबीआई चाहता है जिसमें उसका नाम न हो।
Spudd86

-3

इन फ़ंक्शन को घोषित करने का प्रयास करें जैसे extern "C++"कि आपका कंपाइलर इसका समर्थन करता है, http://msdn.microsoft.com/en-us/library/s6y4zxec(VS.80).aspx


3
यह उन्हें अद्वितीय नाम (शायद नहीं) देने के लिए नाम की मेनिंग बदल सकता है, लेकिन यह अचानक सी अधिभार संकल्प नियम नहीं देगा।
बेन वोइगट

-4

मुझे उम्मीद है कि नीचे दिया गया कोड आपको फंक्शन ओवरलोडिंग को समझने में मदद करेगा

#include <stdio.h>
#include<stdarg.h>

int fun(int a, ...);
int main(int argc, char *argv[]){
   fun(1,10);
   fun(2,"cquestionbank");
   return 0;
}
int fun(int a, ...){
  va_list vl;
  va_start(vl,a);

  if(a==1)
      printf("%d",va_arg(vl,int));
   else
      printf("\n%s",va_arg(vl,char *));
}

2
एक उत्तर में यह बताना चाहिए कि यह क्या कर रहा है और यह क्यों काम करता है। यदि ऐसा नहीं है, तो यह किसी को कुछ भी समझने में कैसे मदद कर सकता है?
अंडरस्कोर_ड

यहां ओवरलोडिंग नहीं है।
melpomene

va_end को कभी नहीं बुलाया गया
user2262111
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.