2009-02-25 39 views
46

va_end - Macro để đặt lại arg_ptr.Chính xác va_end là gì? Nó luôn luôn cần thiết để gọi nó?

Sau khi truy cập danh sách đối số biến, con trỏ arg_ptr thường được đặt lại với va_end(). Tôi hiểu rằng nó là cần thiết nếu bạn muốn tái lặp lại danh sách, nhưng nó thực sự cần thiết nếu bạn không đi? Có thực hành tốt hay không, như quy tắc "luôn có một số default: trong số switch" của bạn?

+1

Đó là một câu hỏi thực sự hay. Tôi muốn ai đó sẽ trả lời nó bằng cách mô tả một kiến ​​trúc nơi va_end không phải là một no-op. – erikkallen

+1

FYI: MSVS2008 - #define _crt_va_end (ap) (ap = (va_list) 0) – Yarik

+0

@erikkallen: Thực hiện tìm kiếm google cho "define va_end" và bạn sẽ tìm thấy một số định nghĩa bất thường có thể hoặc có thể không thực chất là không op. – PlasmaHH

Trả lời

40

va_end được sử dụng để làm sạch. Bạn không muốn đập vỡ ngăn xếp, phải không?

Từ man va_start:

va_end()

Mỗi gọi của va_start() phải được kết hợp bởi một invocation tương ứng của va_end() trong chức năng tương tự. Sau cuộc gọi va_end (ap) biến ap là không xác định. Nhiều traversals của danh sách, mỗi cái được bracket bởi va_start() và va_end() là có thể. va_end() có thể là macro hoặc hàm.

Lưu ý sự hiện diện của từ phải.

Ngăn xếp có thể bị hỏng vì bạn không biết số va_start() đang làm. Các macro va_* có nghĩa là được coi là hộp đen. Mỗi trình biên dịch trên mọi nền tảng đều có thể làm bất cứ điều gì nó muốn ở đó. Nó có thể không làm gì, hoặc nó có thể làm rất nhiều.

Một số ABI vượt qua một vài arg đầu tiên trong sổ đăng ký và phần còn lại trên ngăn xếp. A va_arg() có thể phức tạp hơn. Bạn có thể tra cứu cách một triển khai đã cho thực hiện các vararg, điều này có thể thú vị, nhưng khi viết mã di động, bạn nên coi chúng là các hoạt động mờ đục.

+0

Có nghĩa là con trỏ là 'toàn cục' và khi hàm được gọi lần thứ hai mà không cần đặt lại con trỏ, ngăn xếp sẽ bị hỏng? – Yarik

+3

Nó có thể bị hỏng vì * bạn không biết va_start() đang làm gì. * Nó có thể làm bất cứ điều gì. Và nó cần phải được làm sạch. Do đó, khi bạn gọi va_start(), bạn * PHẢI * khớp nó với va_end(). – greyfade

+0

Cảm ơn bạn đã làm rõ. – Yarik

10

Trong thông thường "thông số được truyền trên ngăn xếp" triển khai, tôi tin rằng va_end() thường là không có gì/trống/null. Tuy nhiên, trên các nền tảng có ít chương trình truyền thống, nó trở nên cần thiết. Đó là một "thực hành tốt" để đưa nó vào nền tảng trung lập.

+0

Nó có thể đặt lại ngăn xếp trong trường hợp bạn không lặp qua tất cả var_args. – Spidey

11

Trên Linux x86-64, chỉ có thể thực hiện một lần truyền qua biến số va_list. Để thực hiện nhiều lần truyền tải hơn, trước tiên nó phải được sao chép bằng cách sử dụng va_copy. man va_copy giải thích chi tiết:

va_copy()

An thực hiện rõ ràng sẽ có một va_list là một con trỏ vào khung đống chức năng variadic.Trong một thiết lập như vậy (đến nay là hầu hết các chung) không có gì chống lại chuyển nhượng dường như

va_list aq = ap; 

Thật không may, cũng có hệ thống mà làm cho nó một mảng của con trỏ (chiều dài 1), và có một nhu cầu

va_list aq; 
    *aq = *ap; 

Cuối cùng, trên các hệ thống mà đối số được truyền trong sổ đăng ký, nó có thể là cần thiết cho va_start() để cấp phát bộ nhớ, lưu trữ các đối số đó, và cũng là một dấu hiệu cho thấy trong đó đối số là tiếp theo, vì vậy va_arg đó () có thể bước thông qua danh sách. Bây giờ va_end() có thể giải phóng bộ nhớ được phân bổ một lần nữa. Để thích ứng với tình huống này, C99 cho biết thêm một va_copy vĩ mô(), vì vậy rằng việc chuyển nhượng trên có thể được thay thế bằng

va_list aq; 
    va_copy(aq, ap); 
    ... 
    va_end(aq); 

Mỗi gọi của va_copy() phải được kết hợp bởi một invoca- tion tương ứng của va_end() trong cùng một chức năng. Một số hệ thống không cung cấp va_copy() có __va_copy thay vào đó, vì đó là tên được sử dụng trong đề xuất dự thảo .

+2

Để cliarfy này; không có gì đặc biệt với Linux x86-64. 'va_copy' là bắt buộc nếu bạn muốn lặp lại hai lần trong danh sách khi bạn chỉ có biến' va_list'. (ví dụ: bên trong một hàm lấy 'va_list' làm đối số). Bạn luôn có thể gọi 'va_start' và' va_end' nhiều như bạn muốn. –

+0

@MattMcNabb Trên x86-64 'va_list' duy trì trạng thái truyền tải. Trên x86 nó không. –

+0

@downvoter có gì sai? –

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