Mã gốc không thành công vì mã cố gắng sử dụng printf()
nơi mã cần sử dụng vprintf()
. Lấy điểm đáng ngờ như logOpen
và logClose
báo cáo theo mệnh giá (cho các ký hiệu, có lẽ họ đang macro mà mở và đóng dòng flog
tập tin), mã nên được:
void logPrintf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
logOpen;
vfprintf(flog, fmt, ap);
logClose;
va_end(ap);
va_list ap2;
va_start(ap2, fmt);
vprintf(fmt, ap2);
va_end(ap2);
}
Không có yêu cầu đặc biệt để sử dụng hai biến số va_list
riêng biệt; bạn hoàn toàn có thể sử dụng cùng một lần hai lần miễn là bạn sử dụng va_end()
trước khi sử dụng lại va_start()
.
void logPrintf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
logOpen;
vfprintf(flog, fmt, ap);
logClose;
va_end(ap);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
Khi một giá trị va_list
được chuyển đến một chức năng (vfprintf()
và vprintf()
trong mã này), bạn nên cho rằng nó không còn có thể sử dụng trong hàm hiện tại. Chỉ an toàn khi gọi số va_end()
trên đó.
Không cần va_copy()
trong mã này. Nó hoạt động, nhưng nó không cần thiết. Bạn cần va_copy()
trong những hoàn cảnh khác, chẳng hạn như khi chức năng của bạn là thông qua một va_list
và bạn cần phải xử lý danh sách hai lần:
void logVprintf(const char *fmt, va_list args1)
{
va_list args2;
va_copy(args2, args1);
logOpen;
vfprintf(flog, fmt, args1);
logClose;
vprintf(fmt, args2);
va_end(args2);
}
Lưu ý rằng trong mã này, đó là trách nhiệm mã gọi để gọi va_end()
trên args1
. Trên thực tế, tiêu chuẩn nói:
Mỗi gọi của va_start
và va_copy
macro được kết hợp bởi một invocation tương ứng của va_end
vĩ mô trong cùng chức năng.
Kể từ khi logVprintf()
chức năng không gọi hoặc va_start
hoặc va_copy
để khởi args1
, nó có thể không hợp pháp gọi va_end
trên args1
. Mặt khác, tiêu chuẩn yêu cầu nó gọi va_end
cho args2
.
Chức năng logPrintf()
có thể được thực hiện trong điều kiện của logVprintf()
bây giờ:
void logPrintf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
logVprintf(fmt, args);
va_end(args);
}
Cấu trúc này - một chức năng hoạt động mà phải mất một va_list
và một hàm bìa mà sẽ đưa ellipsis (arguments biến) và chuyển chúng đến hoạt động sau khi chuyển đổi sang một số va_list
- thường là cách tốt để làm việc. Sớm hay muộn, bạn thường thấy cần thiết cho phiên bản với một đối số va_list
.
Bạn cần sử dụng vprintf lần thứ hai, không phải printf. –