2014-08-28 13 views
7

Gần đây, tôi nhận thấy một trường hợp kỳ lạ Tôi muốn xác minh:Số ký tự cho đến nay trong snprintf

By SUS, cho %n trong một chuỗi định dạng, tương ứng int sẽ được thiết lập để các-lượng-of-byte -kết quả đầu ra. Ngoài ra, đối với snprintf(dest, 3, "abcd"), dest sẽ trỏ đến "ab\0". Tại sao? Vì không có nhiều hơn n (n = 3) byte được ghi vào đầu ra (bộ đệm dest).

Tôi suy luận rằng cho mã:

int written; 
char dest[3]; 
snprintf(dest, 3, "abcde%n", &written); 

written sẽ được thiết lập để 2 (chấm dứt vô loại trừ khỏi count). Nhưng từ thử nghiệm tôi đã thực hiện bằng GCC 4.8.1, written được đặt thành 5. Tôi có hiểu sai tiêu chuẩn không? Nó là một lỗi? Đó là hành vi không xác định?

Edit:

@wildplasser nói:

... hành vi của% n trong chuỗi định dạng có thể không xác định hoặc thực hiện được xác định ...

... việc triển khai phải mô phỏng xử lý chuỗi định dạng hoàn chỉnh (bao gồm% n) ...

@par nói:

written là 5 vì đó là bao nhiêu ký tự này sẽ được ghi tại điểm %n đang gặp phải. Đây là hành vi đúng. snprintf chỉ bản lên đến size nhân vật trừ null dấu ...

Và:

Một cách khác để xem xét điều này là %n sẽ không có thậm chí đã gặp phải nếu nó chỉ xử lý lên đến 2 ký tự, do đó, nó có thể tưởng tượng để mong đợi written để có một giá trị không hợp lệ ...

Và:

... toàn bộ chuỗi được xử lý qua printf() quy tắc, sau đó tối đa độ dài được áp dụng ...

Nó có thể được xác nhận là tiêu chuẩn, một tiêu chuẩn dự thảo hoặc một số nguồn chính thức?

+0

Có vẻ như một lỗi (trong việc triển khai thư viện) với tôi. – pmg

+1

Tôi hy vọng bạn nên * đầu tiên * nhìn vào returnvalue từ snprintf(). Các "tác dụng phụ" là khác nhau; hành vi của '% n' trong chuỗi định dạng có thể là undefined hoặc implementation được định nghĩa nếu returnvalue là> = đối số thứ 2. Trong mọi trường hợp, việc triển khai phải * mô phỏng * xử lý chuỗi định dạng * hoàn thành * (bao gồm '% n') để có được giá trị trả về chính xác, do đó tác dụng phụ có thể thu được khi đang di chuyển. – wildplasser

Trả lời

7

written là 5 vì đó là số lượng ký tự sẽ được viết tại điểm số %n gặp phải. Đây là hành vi đúng. snprintf chỉ sao chép tối đa size ký tự trừ dấu sau (trong trường hợp của bạn 3-1 == 2. Bạn phải tách riêng hành vi định dạng chuỗi khỏi ký tự chỉ ghi nhiều ký tự.

Một cách khác để xem xét điều này là %n thậm chí sẽ không gặp phải nếu nó chỉ xử lý tối đa 2 ký tự, do đó có thể tưởng tượng được là written có giá trị không hợp lệ. Đó là nơi sẽ có một lỗi, nếu bạn đang mong đợi một cái gì đó hợp lệ trong written tại điểm %n đã gặp phải (và không có).

Vì vậy, hãy nhớ, toàn bộ chuỗi được xử lý thông qua các quy tắc printf(), thì chiều dài tối đa được áp dụng.

+1

Hmmm, văn bản của Chuẩn chứa ** "... số ký tự được ghi vào luồng đầu ra cho đến thời điểm này ..." **; ''c'','' d'' và ''e'' không được ghi vào luồng đầu ra – pmg

+1

@pmg - Ký tự * được ghi vào luồng đầu ra, trong khi luồng đầu ra là một bộ đệm dữ liệu" đằng sau hậu trường "trong hàm printf(). * Sau đó * hành vi snprintf chỉ sao chép lên đến kích thước ký tự từ "dòng đầu ra" xảy ra. Xem câu trả lời của Heinz để tham khảo ISOC99. – par

+1

sau đó một lần nữa, có thể văn bản đề cập đến '"% n "' không áp dụng cho 'sprintf()' bởi vì hàm này không ghi vào luồng đầu ra. – pmg

5

Nó không phải là một lỗi: ISOC99 nói

Chức năng snprintf tương đương với fprintf [...] ký tự đầu ra ngoài n-1 được bỏ đi chứ không phải được ghi vào mảng [ ...]

Vì vậy, nó chỉ loại bỏ đầu ra cuối cùng nhưng hoạt động giống nhau.

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