2010-08-20 39 views
71

Vì vậy, tôi có 2 chức năng mà cả hai đều có lập luận tương tựĐi qua đối số biến khác chức năng chấp nhận một danh sách đối số biến

void example(int a, int b, ...); 
void exampleB(int b, ...); 

Bây giờ example cuộc gọi exampleB, nhưng làm thế nào tôi có thể vượt qua cùng các biến trong danh sách đối số biến mà không sửa đổi exampleB (vì điều này cũng đã được sử dụng ở nơi khác).

+5

có thể trùng lặp của [Chuyển tiếp lời gọi hàm variadic trong C] (http://stackoverflow.com/questions/150543/forward-an-invocation-of-a-variadic-function-in-c) –

+0

Vâng giải pháp trên đó là sử dụng vprintf, và đó không phải là trường hợp ở đây. –

Trả lời

79

Bạn không thể thực hiện trực tiếp; bạn phải tạo một hàm mà phải mất một va_list:

#include <stdarg.h> 

static void exampleV(int b, va_list args); 

void example(int a, int b, ...) 
{ 
    va_list args; 
    va_start(args, b); 
    exampleV(b, args); 
    va_end(args); 
} 

void exampleB(int b, ...) 
{ 
    va_list args; 
    va_start(args, b); 
    exampleV(b, args); 
    va_end(args); 
} 

static void exampleV(int b, va_list args) 
{ 
    ...whatever you planned to have exampleB do... 
    ...except it calls neither va_start nor va_end... 
} 
+1

Nghi ngờ tôi phải làm một cái gì đó như thế này, vấn đề là chức năng ví dụ về cơ bản là một wrapper cho vsprintf và không nhiều khác:/ –

+0

@Xeross: Lưu ý rằng điều này không thay đổi đặc điểm kỹ thuật bên ngoài của ví dụB làm gì - nó chỉ thay đổi nội bộ thực hiện. Tôi không chắc vấn đề là gì. –

+1

Tôi đã xử lý nó tương tự như vậy, cảm ơn. –

14

bạn nên tạo các phiên bản của các hàm này có danh sách va_list và chuyển các giá trị đó. Hãy xem vprintf làm ví dụ:

int vprintf (const char * format, va_list arg); 
-1

Sử dụng các tiêu chuẩn C++ 0x mới, bạn có thể để có được làm điều này bằng mẫu variadic hoặc thậm chí chuyển đổi mã cũ sang mẫu cú pháp mới mà không phá vỡ bất cứ điều gì.

+0

tiếc là điều này là không thể trong mọi trường hợp - chỉ cần thử sử dụng lambdas – serup

0

Dựa trên nhận xét rằng bạn đang gói vsprintf và thẻ này được gắn thẻ là C++ Tôi khuyên bạn không nên cố gắng thực hiện việc này, nhưng thay đổi giao diện của bạn để sử dụng C++ iostreams. Chúng có lợi thế hơn các dòng chức năng print, chẳng hạn như loại an toàn và có thể in các mục mà printf sẽ không thể xử lý được. Một số làm lại bây giờ có thể tiết kiệm một số lượng đáng kể đau trong tương lai.

+0

Bạn đang đề cập đến những lợi thế nào? – cjcurrie

+0

@cjcurrie: lợi thế là loại an toàn, ngay cả với các loại do người dùng xác định. Tất nhiên, các hàm C không thể xử lý các kiểu do người dùng định nghĩa. –

2

Ngẫu nhiên, nhiều triển khai C có biến thể v? Printf nội bộ mà IMHO phải là một phần của tiêu chuẩn C. Các chi tiết chính xác khác nhau, nhưng một triển khai điển hình sẽ chấp nhận một cấu trúc có chứa một con trỏ hàm ký tự đầu ra và thông tin cho biết điều gì sẽ xảy ra. Điều này cho phép printf, sprintf và fprintf sử dụng cùng một cơ chế 'cốt lõi'. Ví dụ: vsprintf có thể giống như sau:

 
void s_out(PRINTF_INFO *p_inf, char ch) 
{ 
    (*(p_inf->destptr)++) = ch; 
    p_inf->result++; 
} 

int vsprintf(char *dest, const char *fmt, va_list args) 
{ 
    PRINTF_INFO p_inf; 
    p_inf.destptr = dest; 
    p_inf.result = 0; 
    p_inf.func = s_out; 
    core_printf(&p_inf,fmt,args); 
} 

Hàm core_printf sau đó gọi p_inf-> func cho mỗi ký tự sẽ xuất; chức năng đầu ra sau đó có thể gửi các ký tự đến bàn điều khiển, một tập tin, một chuỗi, hoặc một cái gì đó khác. Nếu triển khai của một người cho thấy hàm core_printf (và bất kỳ cơ chế thiết lập nào nó sử dụng), người ta có thể mở rộng nó với tất cả các loại biến thể.

1

Tôi cũng muốn quấn printf và tìm thấy một câu trả lời hữu ích ở đây:

How to pass variable number of arguments to printf/sprintf

Tôi đã không hề hứng thú trong hoạt động (tôi chắc chắn rằng đoạn mã này có thể được cải thiện trong một số cách, cảm thấy tự do để làm như vậy :)), đây là cho debugprinting tổng quát mà thôi vì vậy tôi đã làm điều này:

//Helper function 
std::string osprintf(const char *fmt, ...) 
{ 
    va_list args; 
    char buf[1000]; 
    va_start(args, fmt); 
    vsnprintf(buf, sizeof(buf), fmt, args); 
    va_end(args); 
    return buf; 
} 

mà tôi sau đó có thể sử dụng như thế này

Point2d p; 

cout << osprintf("Point2d: (%3i, %3i)", p.x, p.y); 
instead of for example: 
cout << "Point2d: (" << setw(3) << p.x << ", " << p.y << ")"; 

Dòng C++ đẹp ở một số khía cạnh, nhưng thực tế trở nên kinh khủng nếu bạn muốn in một cái gì đó như thế này với một số chuỗi nhỏ như dấu ngoặc đơn, dấu hai chấm và dấu phẩy chèn vào giữa các số.

4

lẽ throwin một tảng đá trong một cái ao ở đây, nhưng nó dường như làm việc khá OK với C++ 11 mẫu variadic:

#include <stdio.h> 

template<typename... Args> void test(const char * f, Args... args) { 
    printf(f, args...); 
} 

int main() 
{ 
    int a = 2; 
    test("%s\n", "test"); 
    test("%s %d %d %p\n", "second test", 2, a, &a); 
} 

Ít nhất, nó hoạt động với g++.

Các vấn đề liên quan