2009-03-30 4 views
60

Tôi có khoảng 30 hàm variadic. Mỗi người chấp nhận một con đường như là đối số cuối cùng, ví dụ .:Chuyển dấu chấm lửng sang một hàm variadic khác

bool do_foo(struct *f, int q, const char *fmt, ...) 

Trong mỗi chức năng, tôi phải kiểm tra xem các định dạng mở rộng là ít hơn hoặc bằng một kích thước nhất định. Vì vậy, tôi thấy bản thân mình sao chép/dán cùng một đoạn mã để kiểm tra xem có bao nhiêu ký tự vsnprintf() không in, thiết lập errno cho phù hợp và được bảo lãnh.

Những gì tôi muốn làm là viết một hàm để làm điều này, sẽ trả về một chuỗi được phân bổ tĩnh (mở rộng) được biết là kích thước an toàn hoặc chuỗi mới được khởi tạo thất bại, có thể được kiểm tra với NULL . Các kiểm tra cũng phải xác định nếu chuỗi là một đường dẫn tuyệt đối hoặc tương đối, mà ảnh hưởng đến kích thước an toàn của chuỗi. Đó là rất nhiều mã trùng lặp và nó bắt đầu có mùi.

Có cách nào để tôi có thể chuyển nội dung của elipsis từ chức năng của tôi vào một chức năng khác không? Hoặc tôi có phải gọi va_start() trước tiên, sau đó vượt qua va_list đến chức năng trợ giúp không?

Edit:

Tôi không ở tất cả chứ không phải đi qua các va_list đến helper, tôi chỉ muốn chắc chắn rằng không có gì khác tồn tại. Dường như với tôi trình biên dịch hiểu nơi các đối số variadic bắt đầu, vì vậy tôi đã chỉ tò mò nếu tôi có thể nói với nó để vượt qua chúng cùng.

+0

Có bất kỳ lý do bạn xấu để đi qua các va_list đến helper? – ojblass

+0

Tôi đã phải làm những điều tương tự nhưng phải loại bỏ một vài trong số các args ... không phải là mã dễ chịu để duy trì. – ojblass

Trả lời

63

Bạn không thể, bạn chỉ có thể chuyển đối số dưới dạng va_list. Xem comp.lang.c FAQ. Nói chung, nếu bạn đang viết hàm variadic (có nghĩa là, các hàm có số lượng đối số) trong C, bạn nên viết hai phiên bản của mỗi hàm: một phiên bản có dấu ba chấm (...) và một mất va_list. Phiên bản lấy dấu ba chấm nên gọi va_start, gọi phiên bản lấy số va_list, gọi va_end và trả lại. Không cần sao chép mã giữa hai phiên bản của hàm, vì một phiên bản gọi hàm kia.

+5

Sẽ rất tuyệt nếu bạn viết mã. –

+0

Tôi nên làm gì nếu tôi cần phải làm việc với 'va_list' hai lần? Thông thường, tôi phải gọi 'va_end' và' va_start' giữa các tập quán (nếu không là UB), nhưng tôi không thể gọi nó trong một hàm có 'va_list':' 'va_start' được sử dụng với hàm args' cố định . –

+1

Nevermind, figured it out - Tôi cần phải sử dụng 'va_copy' cho mỗi lần sử dụng tiếp theo. –

0

Bạn phải chuyển va_list cho người trợ giúp.

+1

Câu trả lời này là cách để trở nên hữu ích. Nó nên được mở rộng với các chi tiết bổ sung hữu ích hoặc bị loại bỏ. – rjstelling

+0

@rjstelling Tôi thấy câu trả lời này hữu ích khi tôi đặt câu hỏi.Nếu bạn nhận thấy, tôi chỉ ra rằng về cơ bản tôi đã chấp nhận để vượt qua va_list, nhưng cảm thấy như có thể có một cách khác để thực hiện nó. Andrew khẳng định khá nhiều rằng không có ai (không có phép thuật biên dịch tôi có thể sử dụng). Trong khi các câu trả lời khác đi sâu hơn, điều này đã trả lời đủ câu hỏi của tôi. –

9

Có lẽ bạn có thể sử dụng các macro variadic - như sau:

#define FOO(...) do { do_some_checks; myfun(__VA_ARGS__); } while (0) 

NB! Macro biến thể là C99 chỉ

+0

Tôi đã nhìn vào những người, mà tiết kiệm cho tôi từ việc phải thêm một wrapper xung quanh chức năng mà thực sự không viết. –

+0

c99 là không có vấn đề, chương trình của tôi là khá gcc/linux cụ thể –

-1

Tôi không biết điều này có hữu ích không, bạn có thể truy cập các biến theo tham chiếu. Đây là một thủ thuật lén lút, nhưng thật không may sẽ không cho phép bạn sử dụng dấu ba chấm trong định nghĩa hàm cuối cùng.

#include <stdio.h> 

void print_vars(int *n) 
{ 
    int i; 
    for(i=0;i<=*n;i++) 
    printf("%X %d ", (int)(n+i), *(n+i)); 
    printf("\n"); 
} 

void pass_vars(int n, ...) 
{ 
    print_vars(&n); 
} 

int main() 
{ 
    pass_vars(4, 6, 7, 8, 0); 
    return 0; 
} 

Mở máy của tôi nó ra

$ ./a.out 
BFFEB0B0 4 BFFEB0B4 6 BFFEB0B8 7 BFFEB0BC 8 BFFEB0C0 0 
+9

Không di động ... – aschepler