Bagaimana cara mencapai fungsi berlebih di C?


241

Apakah ada cara untuk mencapai kelebihan fungsi di C? Saya melihat fungsi sederhana menjadi kelebihan beban

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

Saya pikir tidak ada jalan lurus ke depan; Saya mencari solusi jika ada.


6
Mengapa Anda ingin melakukan ini? C tidak memiliki kemampuan polimorfik. Jadi foo (tipe acak) tidak mungkin. Hanya membuat funcs nyata foo_i, foo_ch, foo_d, dll
jmucchiello

4
Anda bisa menggunakan cara jahat menggunakan pointer batal dan mengetik id.
alk

11
Saya merasa saya harus menarik perhatian pada fakta bahwa jawaban untuk pertanyaan ini telah berubah sejak awalnya ditanyakan , dengan standar C yang baru.
Leushenko

Jawaban:


127

Ada beberapa kemungkinan:

  1. fungsi gaya printf (ketik sebagai argumen)
  2. fungsi gaya pembuka (ketikkan nama fungsi)
  3. c subset dari c ++ (jika Anda dapat menggunakan c ++ compiler)

1
dapatkah Anda menjelaskan atau memberikan tautan untuk fungsi gaya pembuka?
FL4SOF

1
@ Lazer: Inilah salah satu implementasi fungsi printf seperti sederhana.
Alexey Frunze

12
Tidak. Printf tidak berfungsi dengan berlebihan. ini menggunakan vararg !!! Dan C tidak mendukung Function Overloading.
hqt

52
@ hqt Jawabannya tidak pernah menyebutkan kata overloading.
Kyrias

1
@kyria Jika jawabannya bukan tentang kelebihan muatan, itu ada pada pertanyaan yang salah
Michael Mrozek

233

Iya!

Sejak pertanyaan ini diajukan, standar C (tidak ada ekstensi) telah secara efektif mendapatkan dukungan untuk kelebihan fungsi (bukan operator), berkat penambahan _Generickata kunci di C11. (didukung dalam GCC sejak versi 4.9)

(Overloading tidak benar-benar "built-in" dalam mode yang ditunjukkan dalam pertanyaan, tapi mati-matian mudah untuk mengimplementasikan sesuatu yang berfungsi seperti itu.)

_Genericadalah operator waktu kompilasi dalam keluarga yang sama dengan sizeofdan _Alignof. Ini dijelaskan dalam bagian standar 6.5.1.1. Ia menerima dua parameter utama: ekspresi (yang tidak akan dievaluasi saat runtime), dan daftar asosiasi tipe / ekspresi yang terlihat agak seperti switchblok. _Genericdapatkan keseluruhan jenis ekspresi dan kemudian "aktifkan" untuk memilih ekspresi hasil akhir dalam daftar untuk jenisnya:

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

Ekspresi di atas mengevaluasi ke 2- jenis ekspresi pengendali int, jadi ia memilih ekspresi yang terkait dengan intnilainya. Tidak ada yang tersisa saat runtime. ( defaultKlausa ini opsional: jika Anda membiarkannya dan jenisnya tidak cocok, itu akan menyebabkan kesalahan kompilasi.)

Cara ini berguna untuk kelebihan fungsi adalah dapat dimasukkan oleh preprocessor C dan memilih ekspresi hasil berdasarkan pada jenis argumen yang diteruskan ke makro pengontrol. Jadi (contoh dari standar C):

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

Makro ini menerapkan cbrtoperasi kelebihan beban , dengan mengirimkan jenis argumen ke makro, memilih fungsi implementasi yang sesuai, dan kemudian meneruskan argumen makro asli ke fungsi tersebut.

Jadi untuk menerapkan contoh asli Anda, kami bisa melakukan ini:

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

Dalam hal ini kita bisa menggunakan default:asosiasi untuk kasus ketiga, tetapi itu tidak menunjukkan bagaimana memperluas prinsip ke beberapa argumen. Hasil akhirnya adalah bahwa Anda dapat menggunakan foo(...)kode Anda tanpa khawatir (banyak [1]) tentang jenis argumennya.


Untuk situasi yang lebih rumit, misalnya fungsi yang kelebihan jumlah argumen yang lebih besar, atau jumlah yang bervariasi, Anda dapat menggunakan makro utilitas untuk secara otomatis menghasilkan struktur pengiriman statis:

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"
}

( implementasi di sini ) Jadi, dengan sedikit usaha, Anda dapat mengurangi jumlah pelat ketel agar tampak seperti bahasa dengan dukungan asli untuk kelebihan muatan.

Selain itu , sudah dimungkinkan untuk membebani jumlah argumen (bukan tipe) di C99.


[1] perhatikan bahwa cara C mengevaluasi tipe mungkin membuat Anda tersandung. Ini akan memilih foo_intjika Anda mencoba memberikan karakter literal, misalnya, dan Anda perlu sedikit mengacaukannya jika Anda ingin overload Anda mendukung string literal. Namun secara keseluruhan masih cukup keren.


Berdasarkan contoh Anda, sepertinya satu-satunya kelebihan beban adalah fungsi seperti makro. Biarkan saya melihat apakah saya mengerti dengan benar: Jika Anda ingin membebani fungsi Anda hanya akan menggunakan preprocessor untuk mengalihkan panggilan fungsi berdasarkan pada tipe data yang diteruskan, kan?
Nick

Sayangnya, setiap kali C11 mulai menangkap saya berasumsi MISRA tidak akan merangkul fitur ini karena alasan yang sama mereka melarang daftar argumen variabel. Saya mencoba untuk tetap dekat dengan MISRA di dunia saya.
Nick

9
@Nick itu semua overloading. Itu hanya ditangani secara implisit dalam bahasa lain (mis. Anda tidak bisa benar-benar mendapatkan "pointer ke fungsi yang kelebihan beban" dalam bahasa apa pun, karena kelebihan muatan menyiratkan beberapa badan). Perhatikan bahwa ini tidak dapat dilakukan oleh preprosesor saja, ini membutuhkan pengiriman jenis tertentu; preprocessor hanya mengubah tampilannya.
Leushenko

1
Sebagai seseorang yang cukup akrab dengan C99 dan ingin belajar bagaimana melakukan ini, ini tampaknya terlalu rumit, bahkan untuk C.
Tyler Crompton

5
@TylerCrompton Dievaluasi pada waktu kompilasi.
JAB

75

Seperti yang telah dinyatakan, kelebihan dalam arti yang Anda maksud tidak didukung oleh C. Ungkapan umum untuk menyelesaikan masalah adalah membuat fungsi menerima gabungan yang ditandai . Ini diimplementasikan oleh structparameter, di mana structitu sendiri terdiri dari semacam indikator jenis, seperti enum, dan uniondari berbagai jenis nilai. Contoh:

#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
Mengapa tidak akan Anda hanya membuat semua whatevers menjadi fungsi yang terpisah ( set_int, set_float, dll). Kemudian "penandaan dengan tipe" menjadi "tambahkan nama tipe ke nama fungsi". Versi dalam jawaban ini melibatkan lebih banyak pengetikan, lebih banyak biaya runtime, lebih banyak kemungkinan kesalahan yang tidak akan tertangkap saat kompilasi ... Saya gagal melihat keuntungan sama sekali untuk melakukan hal-hal dengan cara ini! 16 suara positif ?!
Ben

20
Ben, jawaban ini dibatalkan karena menjawab pertanyaan, alih-alih hanya mengatakan "jangan lakukan itu". Anda benar bahwa lebih idiomatik dalam C untuk menggunakan fungsi terpisah, tetapi jika seseorang menginginkan polimorfisme dalam C, ini adalah cara yang baik untuk melakukannya. Lebih lanjut, jawaban ini menunjukkan bagaimana Anda akan mengimplementasikan run-time polymorphism di kompiler atau VM: beri tag nilai dengan tipe, dan kemudian kirimkan berdasarkan itu. Karena itu, ini merupakan jawaban yang sangat baik untuk pertanyaan awal.
Nils von Barth

20

Berikut adalah contoh paling jelas dan paling ringkas yang saya temukan mendemonstrasikan kelebihan fungsi di 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
Saya pikir ini adalah dupe dari stackoverflow.com/a/25026358/1240268 dalam semangat (tetapi dengan sedikit penjelasan).
Andy Hayden

1
Saya pasti lebih suka 1 blok terus menerus lengkap dan kode runnable ke memotong dan dicincang yang # 1240268. Untuk masing-masing.
Jay Taylor

1
Saya lebih suka jawaban yang menjelaskan apa yang mereka lakukan dan mengapa mereka bekerja. Ini tidak ada. "Terbaik yang pernah saya lihat:" bukan eksposisi.
underscore_d

19

Jika kompiler Anda adalah gcc dan Anda tidak keberatan melakukan pembaruan tangan setiap kali Anda menambahkan kelebihan baru Anda dapat melakukan beberapa keajaiban makro dan mendapatkan hasil yang Anda inginkan dari segi penelepon, tidak baik untuk menulis ... tetapi mungkin saja

lihat __builtin_types_compatible_p, lalu gunakan untuk mendefinisikan makro yang melakukan sesuatu seperti

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

tapi ya jahat, hanya saja jangan

EDIT: C1X akan mendapatkan dukungan untuk tipe ekspresi generik yang terlihat seperti ini:

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

13

Ya, semacam.

Ini contohnya:

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);
}

Ini akan menampilkan 0 dan halo .. dari printA dan printB.


2
int main (int argc, char ** argv) {int a = 0; cetak (a); print ("hello"); return (EXIT_SUCCESS); } akan menampilkan 0 dan halo .. dari printA dan printB ...
Captain Barbossa

1
__builtin_types_compatible_p, bukankah itu kompiler GCC spesifik?
Sogartar

11

Pendekatan berikut mirip dengan a2800276 , tetapi dengan beberapa makro C99 ditambahkan:

// 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

Ini mungkin tidak membantu sama sekali, tetapi jika Anda menggunakan dentang Anda dapat menggunakan atribut overloadable - Ini berfungsi bahkan ketika dikompilasi sebagai C

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

Header

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

Penerapan

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

10

Dalam arti yang Anda maksud - tidak, Anda tidak bisa.

Anda dapat mendeklarasikan va_argfungsi seperti

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

, tetapi Anda harus memberikan beberapa jenis informasi tentang jumlah variabel dan jenisnya dalam argumen pertama - seperti yang printf()dilakukan.


6

Biasanya kutil untuk menunjukkan jenis ditambahkan atau diawali dengan nama. Anda bisa lolos dengan makro adalah beberapa contoh, tetapi itu tergantung pada apa yang Anda coba lakukan. Tidak ada polimorfisme di C, hanya paksaan.

Operasi generik sederhana dapat dilakukan dengan makro:

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

Jika kompiler Anda mendukung typeof , operasi yang lebih rumit dapat dimasukkan ke makro. Anda kemudian dapat memiliki simbol foo (x) untuk mendukung jenis operasi yang sama berbeda, tetapi Anda tidak dapat memvariasikan perilaku di antara kelebihan beban yang berbeda. Jika Anda menginginkan fungsi yang sebenarnya daripada makro, Anda mungkin dapat menempelkan tipe ke nama dan menggunakan tempelan kedua untuk mengaksesnya (saya belum mencoba).


dapatkah Anda menjelaskan sedikit lebih banyak tentang pendekatan berbasis makro.
FL4SOF

4

Jawaban Leushenko benar-benar keren - semata-mata: foocontohnya tidak dikompilasi dengan GCC, yang gagal pada foo(7), tersandung FIRSTmakro dan panggilan fungsi yang sebenarnya ( (_1, __VA_ARGS__), tetap dengan koma surplus. Selain itu, kami dalam masalah jika kami ingin memberikan kelebihan tambahan , seperti foo(double).

Jadi saya memutuskan untuk menguraikan jawaban sedikit lebih jauh, termasuk untuk memungkinkan kekosongan yang berlebihan ( foo(void)- yang menyebabkan beberapa masalah ...).

Gagasannya sekarang adalah: Tetapkan lebih dari satu generik dalam makro yang berbeda dan biarkan pilih yang benar sesuai dengan jumlah argumen!

Jumlah argumen cukup mudah, berdasarkan jawaban ini :

#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

Itu bagus, kami memutuskan untuk salah satu SELECT_1atau SELECT_2(atau lebih banyak argumen, jika Anda ingin / membutuhkannya), jadi kami hanya perlu mendefinisikan yang tepat:

#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     \
        )                               \
)

OK, saya sudah menambahkan void overload - namun, ini sebenarnya tidak tercakup oleh standar C, yang tidak memungkinkan argumen variadik kosong, yaitu kita kemudian bergantung pada ekstensi kompilator !

Pada awalnya, panggilan makro kosong ( foo()) masih menghasilkan token, tetapi yang kosong. Jadi makro penghitungan sebenarnya mengembalikan 1 bukannya 0 bahkan pada panggilan makro kosong. Kita dapat "dengan mudah" menghilangkan masalah ini, jika kita menempatkan koma setelah __VA_ARGS__ kondisional , tergantung pada daftar yang kosong atau tidak:

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

Itu terlihat mudah, tetapi COMMAmakronya cukup berat; untungnya, topik ini sudah dibahas di blog Jens Gustedt (terima kasih, Jens). Trik dasarnya adalah fungsi makro tidak diperluas jika tidak diikuti oleh tanda kurung, untuk penjelasan lebih lanjut, lihat blog Jens ... Kita hanya perlu memodifikasi makro sedikit untuk kebutuhan kita (saya akan menggunakan nama yang lebih pendek dan lebih sedikit argumen untuk singkatnya).

#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 ,

Dan sekarang kita baik-baik saja ...

Kode lengkap dalam satu blok:

/*
 * 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

Tidak bisakah Anda menggunakan C ++ dan tidak menggunakan semua fitur C ++ lainnya kecuali yang ini?

Jika masih ada C ketat saja maka saya akan merekomendasikan fungsi variadic sebagai gantinya.


3
Tidak jika kompiler C ++ tidak tersedia untuk OS yang dikodekannya.
Brian

2
tidak hanya itu tetapi dia mungkin menginginkan ABI C yang tidak memiliki nama mangling di dalamnya.
Spudd86


-4

Saya harap kode di bawah ini akan membantu Anda untuk memahami kelebihan fungsi

#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
Sebuah jawaban harus menjelaskan apa yang dilakukannya dan mengapa itu berhasil. Jika tidak, bagaimana bisa membantu orang memahami sesuatu?
underscore_d

Tidak ada kelebihan beban di sini.
melpomene

va_end tidak pernah dipanggil
user2262111
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.