Đối số mặc định C


279

Có cách nào để xác định đối số mặc định cho hàm trong C không?


6
chỉ muốn một C tốt hơn một chút, không phải C ++. nghĩ C +. với một loạt các cải tiến nhỏ được nâng lên từ C ++, nhưng không phải là mớ hỗn độn lớn. Và, xin vui lòng, không có trình tải liên kết khác nhau. nên chỉ là một bước giống như tiền xử lý. chuẩn hóa. ở mọi nơi ...
ivo Welch

Câu hỏi liên quan mà tôi không thấy được liệt kê trong thanh bên.
Shelby Moore III

Tôi muốn nói dừng lại là một kẻ man rợ và học cách sử dụng C ++ (11, ...) tốt - jk! / tôi dập tắt ngọn lửa ... nhưng ... bạn sẽ yêu nó ... hahaha tôi không thể tự giúp mình, xin lỗi.
psychboom 17/03/2017

Câu trả lời:


147

Không hẳn vậy. Cách duy nhất là viết hàm varargs và điền thủ công các giá trị mặc định cho các đối số mà người gọi không vượt qua.


22
Tôi ghét việc thiếu kiểm tra khi sử dụng varargs.
dmckee --- ex-moderator mèo con

16
Cũng như bạn nên; Tôi thực sự không khuyên bạn điều này; Tôi chỉ muốn truyền đạt rằng nó có thể.
Eli Courtwright

4
Tuy nhiên, làm thế nào để bạn muốn kiểm tra xem người gọi có vượt qua đối số hay không? Tôi nghĩ để nó hoạt động, bạn không có người gọi để nói với bạn rằng anh ta đã không vượt qua nó? Tôi nghĩ rằng điều này làm cho toàn bộ cách tiếp cận ít sử dụng hơn - người gọi cũng có thể gọi một chức năng với một tên khác.
Julian Schaub - litb

3
Cuộc open(2)gọi hệ thống sử dụng điều này cho một đối số tùy chọn có thể có mặt tùy thuộc vào các đối số được yêu cầu và printf(3)đọc một chuỗi định dạng chỉ định số lượng đối số sẽ có. Cả hai đều sử dụng varargs khá an toàn và hiệu quả, và mặc dù bạn chắc chắn có thể làm hỏng chúng, printf()đặc biệt là dường như khá phổ biến.
Chris Lutz

4
@Eli: Không phải tất cả các trình biên dịch C đều là gcc. Có một số phép thuật trình biên dịch nâng cao đang diễn ra để cảnh báo khi printf () của bạn không khớp với chuỗi định dạng của bạn. Và tôi không nghĩ rằng có thể nhận được các cảnh báo tương tự cho các hàm biến đổi của riêng bạn (trừ khi chúng sử dụng cùng một kiểu chuỗi định dạng).
tomlogic

280

Wow, mọi người đều là một người bi quan như vậy quanh đây. Câu trả lời là có.

Điều đó không tầm thường: cuối cùng, chúng ta sẽ có chức năng cốt lõi, cấu trúc hỗ trợ, chức năng trình bao bọc và macro xung quanh chức năng trình bao bọc. Trong công việc của tôi, tôi có một bộ macro để tự động hóa tất cả điều này; một khi bạn hiểu được dòng chảy, bạn sẽ dễ dàng làm điều tương tự.

Tôi đã viết nó ở nơi khác, vì vậy đây là một liên kết bên ngoài chi tiết để bổ sung tóm tắt ở đây: http://modelingwithdata.org/arch/00000022.htm

Chúng tôi muốn biến

double f(int i, double x)

vào một hàm lấy mặc định (i = 8, x = 3.14). Xác định cấu trúc đồng hành:

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

Đổi tên hàm của bạn f_basevà xác định hàm bao bọc đặt mặc định và gọi cơ sở:

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

Bây giờ thêm một macro, sử dụng macro matrixdic của C. Bằng cách này, người dùng không cần phải biết rằng họ thực sự đang tạo ra một f_argscấu trúc và nghĩ rằng họ đang làm như bình thường:

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

OK, bây giờ tất cả những điều sau đây sẽ hoạt động:

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

Kiểm tra các quy tắc về cách khởi tạo ghép đặt mặc định cho các quy tắc chính xác.

Một điều không hoạt động: f(0) , bởi vì chúng ta không thể phân biệt giữa giá trị còn thiếu và số không. Theo kinh nghiệm của tôi, đây là điều cần chú ý, nhưng có thể được quan tâm khi có nhu cầu --- một nửa thời gian mặc định của bạn thực sự bằng không.

Tôi đã trải qua những rắc rối khi viết nó lên bởi vì tôi nghĩ rằng các đối số và mặc định được đặt tên thực sự làm cho việc mã hóa trong C dễ dàng hơn và thậm chí thú vị hơn. Và C thật tuyệt vời vì quá đơn giản và vẫn có đủ ở đó để biến tất cả những điều này thành có thể.


16
+1 sáng tạo! Nó có những hạn chế nhưng cũng mang lại các tham số được đặt tên cho bảng. Lưu ý rằng, {}(trình khởi tạo trống) là lỗi C99.
u0b34a0f6ae

28
Tuy nhiên, đây là một điều tuyệt vời cho bạn: Tiêu chuẩn cho phép chỉ định các thành viên được đặt tên nhiều lần, ghi đè sau này. Vì vậy, đối với các tham số có tên chỉ bạn mới có thể giải quyết vấn đề mặc định và cho phép thực hiện cuộc gọi trống. #define vrange(...) CALL(range,(param){.from=1, .to=100, .step=1, __VA_ARGS__})
u0b34a0f6ae

3
Tôi hy vọng các lỗi biên dịch có thể đọc được, nhưng đây là một kỹ thuật tuyệt vời! Hầu như trông giống như con trăn kwargs.
totowtwo

6
@RunHolt Trong khi chắc chắn đơn giản hơn, nó không khách quan hơn; các tham số được đặt tên đi kèm với các lợi ích như dễ đọc của các cuộc gọi (với chi phí dễ đọc của mã nguồn). Một cái tốt hơn cho các nhà phát triển nguồn, cái kia tốt hơn cho người dùng chức năng. Có một chút vội vàng khi chỉ cần ném ra "cái này tốt hơn!"
Alice

3
@DawidPi: C11 6.7.9 (19), khi khởi tạo tập hợp: "tất cả các tiểu dự án không được khởi tạo rõ ràng sẽ được khởi tạo hoàn toàn giống như các đối tượng có thời lượng lưu trữ tĩnh" Và như bạn biết, các phần tử thời lượng tĩnh được khởi tạo bằng không | NULL | \ 0. [Điều này cũng ở c99.]
bk.

161

Đúng. :-) Nhưng không phải theo cách bạn mong đợi.

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

Thật không may, C không cho phép bạn quá tải các phương thức để bạn kết thúc với hai chức năng khác nhau. Tuy nhiên, bằng cách gọi f2, bạn thực sự sẽ gọi F1 với giá trị mặc định. Đây là giải pháp "Đừng lặp lại chính mình", giúp bạn tránh sao chép / dán mã hiện có.


24
FWIW, tôi muốn sử dụng số ở cuối hàm để chỉ ra số lượng đối số cần có. Làm cho nó dễ dàng hơn là chỉ sử dụng bất kỳ số tùy ý. :)
Macke

4
Đây là câu trả lời tốt nhất bởi vì nó cho thấy một cách đơn giản để thực hiện cùng một mục tiêu. Tôi có một chức năng là một phần của API cố định mà tôi không muốn thay đổi, nhưng tôi cần nó để có một thông số mới. Tất nhiên, rõ ràng đến mức tôi đã bỏ lỡ nó (bị mắc kẹt khi nghĩ về thông số mặc định!)
RunHolt

4
f2 cũng có thể là macro tiền xử lý
osvein

41

Chúng ta có thể tạo các hàm sử dụng các tham số được đặt tên (chỉ) cho các giá trị mặc định. Đây là phần tiếp theo của câu trả lời của bk.

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

Tiêu chuẩn C99 xác định rằng các tên sau này trong phần khởi tạo ghi đè lên các mục trước đó. Chúng ta cũng có thể có một số tham số vị trí tiêu chuẩn, chỉ cần thay đổi chữ ký macro và hàm cho phù hợp. Các tham số giá trị mặc định chỉ có thể được sử dụng theo kiểu tham số được đặt tên.

Đầu ra chương trình:

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

2
Đây có vẻ như là một triển khai dễ dàng và thẳng hơn so với giải pháp Wim ten Brink hoặc BK. Có bất kỳ nhược điểm nào đối với việc thực hiện này mà những người khác cũng không sở hữu không?
stephenmm

24

OpenCV sử dụng một cái gì đó như:

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

Nếu người dùng không biết mình nên viết gì, thủ thuật này có thể hữu ích:

ví dụ sử dụng


19

Không.

Ngay cả tiêu chuẩn C99 mới nhất cũng không hỗ trợ điều này.


không đơn giản sẽ tốt hơn nữa;)
KevinDTimm

21
@kevindtimm: Điều đó là không thể, SO bắt buộc độ dài tối thiểu cho câu trả lời. Tôi đã thử. :)
thư giãn

2
Hãy tham khảo câu trả lời của tôi. :)
hỗn loạn

18

Không, đó là một tính năng ngôn ngữ C ++.


14

Câu trả lời ngắn gọn: Không.

Câu trả lời dài hơn một chút: Có một cách giải quyết , , nơi bạn truyền một chuỗi mà bạn phân tích cho các đối số tùy chọn:

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

trong đó opt có thể bao gồm cặp "name = value" hoặc thứ gì đó và bạn sẽ gọi như thế nào

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

Rõ ràng điều này chỉ đôi khi hữu ích. Nói chung khi bạn muốn một giao diện duy nhất cho một họ chức năng.


Bạn vẫn tìm thấy cách tiếp cận này trong các mã vật lý hạt được viết bởi các chương trình chuyên nghiệp trong c ++ (ví dụ như ROOT ). Ưu điểm chính của nó là nó có thể được mở rộng gần như vô thời hạn trong khi vẫn duy trì khả năng tương thích trở lại.


2
Kết hợp điều này với varargs và bạn đã có tất cả các loại niềm vui!
David Thornley

5
Tôi sẽ sử dụng một tùy chỉnh structvà yêu cầu người gọi thực hiện một, điền vào các trường cho các tùy chọn khác nhau, sau đó chuyển nó theo địa chỉ hoặc chuyển NULLcho các tùy chọn mặc định.
Chris Lutz

Sao chép các mẫu mã từ ROOT là một ý tưởng khủng khiếp!
innisfree

13

Có lẽ cách tốt nhất để làm điều này (có thể hoặc không thể trong trường hợp của bạn tùy thuộc vào tình huống của bạn) là chuyển sang C ++ và sử dụng nó như một 'C tốt hơn'. Bạn có thể sử dụng C ++ mà không cần sử dụng các lớp, mẫu, nạp chồng toán tử hoặc các tính năng nâng cao khác.

Điều này sẽ cung cấp cho bạn một biến thể của C với chức năng nạp chồng và các tham số mặc định (và bất kỳ tính năng nào khác bạn chọn sử dụng). Bạn chỉ cần có một chút kỷ luật nếu bạn thực sự nghiêm túc về việc chỉ sử dụng một tập hợp con bị hạn chế của C ++.

Nhiều người sẽ nói rằng đó là một ý tưởng tồi tệ khi sử dụng C ++ theo cách này và họ có thể có một điểm. Nhưng đó chỉ là một ý kiến; Tôi nghĩ việc sử dụng các tính năng của C ++ là hợp lệ mà bạn không cần phải mua toàn bộ. Tôi nghĩ rằng một phần quan trọng của lý do cho sự thành công của C ++ là nó đã được sử dụng bởi rất nhiều lập trình viên trong những ngày đầu tiên theo cách chính xác.


13

Một tùy chọn khác sử dụng structs:

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

Không.


2
cách giải quyết là gì? Tôi có thể thấy rằng nó là 20202020hex, nhưng làm thế nào để tôi gõ nó?
Lazer

5

Một mẹo khác sử dụng macro:

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

Nếu chỉ có một đối số được thông qua, bsẽ nhận giá trị mặc định (trong trường hợp này là 15)


4

Không, nhưng bạn có thể cân nhắc sử dụng một tập hợp các hàm (hoặc macro) để tính gần đúng bằng cách sử dụng các đối số mặc định:

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

Có, với các tính năng của C99, bạn có thể làm điều này. Điều này hoạt động mà không xác định cấu trúc dữ liệu mới hoặc như vậy và không có chức năng phải quyết định trong thời gian chạy cách nó được gọi và không có bất kỳ chi phí tính toán nào.

Để được giải thích chi tiết, xem bài viết của tôi tại

http://gustyt.wordpress.com/2010/06/03/default-argument-for-c99/

Jens


Seel cũng câu trả lời của tôi có nguồn gốc từ bạn.
Shelby Moore III

1
Nội tuyến một ví dụ.
dùng877329

3

Nói chung là không, nhưng trong gcc Bạn có thể đặt tham số cuối cùng của funcA () với một macro.

Trong funcB () tôi sử dụng một giá trị đặc biệt (-1) để báo hiệu rằng tôi cần giá trị mặc định cho tham số 'b'.

#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

Tôi đã cải thiện câu trả lời của Jens Gustyt để:

  1. chức năng nội tuyến không được sử dụng
  2. mặc định được tính trong quá trình tiền xử lý
  3. macro có thể tái sử dụng
  4. có thể đặt lỗi trình biên dịch phù hợp với trường hợp không đủ đối số cho các mặc định được phép
  5. mặc định không bắt buộc phải tạo đuôi của danh sách tham số nếu các loại đối số sẽ không rõ ràng
  6. tương tác với C11 _Generic
  7. thay đổi tên hàm theo số lượng đối số!

Đột biến.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

Kịch bản sử dụng đơn giản hóa:

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__)

Và với _Generic:

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__))

Và với lựa chọn tên hàm matrixdic, không thể kết hợp với _Generic:

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

ĐÚNG

Thông qua các macro

3 thông số:

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

Nếu bạn muốn đối số thứ 4, thì cần thêm my_func3. Lưu ý các thay đổi trong VAR_FUNC, my_func2 và my_func

4 thông số:

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

Chỉ ngoại lệ rằng các biến float không thể được đưa ra các giá trị mặc định ( trừ khi đó là đối số cuối cùng như trong trường hợp 3 tham số ), bởi vì chúng cần dấu chấm ('.'), Không được chấp nhận trong các đối số macro. Nhưng có thể tìm ra một công việc xung quanh như đã thấy trong macro my_func2 ( gồm 4 trường hợp tham số )

Chương trình

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

Đầu ra:

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

Vâng, bạn có thể làm một cái gì đó simulair, ở đây bạn phải biết các danh sách đối số khác nhau bạn có thể nhận được nhưng bạn có cùng chức năng để xử lý tất cả.

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

Tại sao chúng ta không thể làm điều này.

Cung cấp cho đối số tùy chọn một giá trị mặc định. Theo cách đó, người gọi hàm không nhất thiết phải truyền giá trị của đối số. Đối số lấy giá trị mặc định. Và dễ dàng tranh luận đó trở thành tùy chọn cho khách hàng.

Ví dụ

void foo (int a, int b = 0);

Ở đây b là một đối số tùy chọn.


10
Cái nhìn sâu sắc tuyệt vời, vấn đề là C không hỗ trợ các đối số tùy chọn hoặc các hàm quá tải, vì vậy giải pháp trực tiếp không biên dịch.
Thomas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.