2012-07-10 40 views
5

thể trùng lặp:
warning: format not a string literal and no format argumentsTại sao printf (char []) tạo ra một cảnh báo, trong khi đó printf ("asdf") không

Tôi có câu hỏi rất đơn giản: Tại sao khi Tôi thực hiện char[] s = "hi"; printf(s) nó đưa ra cảnh báo: "cảnh báo: định dạng không phải là chuỗi ký tự và không có đối số định dạng", trong khi đó printf("aa") thì không.

Tôi đã đọc một sự khác biệt giữa mảng char và chuỗi chữ (một là const char const* và khác là char*), nhưng từ printf() chữ ký:

http://www.gnu.org/software/libc/manual/html_node/Formatted-Output-Functions.html#Formatted-Output-Functions

tôi thấy rằng nó phù hợp cho bất kỳ đó loại. Vì vậy, câu hỏi của tôi là lý do tại sao printf("aaa") không phát hành bất kỳ cảnh báo nào (bằng cách nào đó nó kiểm tra rằng chữ là một const, mảng trong khi đó không phải là)?

+0

FWIW, VC++ không khiếu nại về các chữ không liên tục. – Mysticial

+0

Trình biên dịch nào thực hiện điều này với mã của bạn? – Jay

+0

@ Tâm lý, tôi đồng ý. VC không phàn nàn. Tự hỏi tại sao trình biên dịch khác tuân thủ hoặc tại sao VC không? – Jay

Trả lời

6

Trình biên dịch GNU và rất nhiều trình biên dịch khác những ngày này thực sự kiểm tra chuỗi định dạng cho printf -family chống lại các đối số cung cấp. Trình biên dịch cảnh báo rằng nó không thể làm điều này cho các chuỗi không phải chữ.

Sử dụng chuỗi định dạng không theo nghĩa đen được coi là thực hành không tốt. Sử dụng một chuỗi định dạng mà bạn không kiểm soát là tồi tệ hơn nhiều.

+0

Nếu tôi hiểu bạn một cách chính xác, bạn đang nói rằng vì chuỗi ký tự được sao chép vào một mảng, trình biên dịch không biết mảng đó chứa gì tại thời gian biên dịch , do đó, nó không thể kiểm tra xem nó có phải là một chuỗi định dạng tốt cùng với các đối số được cung cấp hay không. – dhblah

+0

Nhưng tại sao sau đó 'const char * s =" hi "; printf (s) 'cũng tạo ra cảnh báo? – dhblah

+0

Ồ, tôi tìm thấy nó 'const char const * s =" hi "; printf (s) 'không sản xuất bất kỳ lỗi nào. Vì vậy, 'const char const *' có vẻ là kiểu chuỗi ký tự. – dhblah

1

Tôi đặt cược trong trường hợp thứ hai trình biên dịch thấy rằng chuỗi không có định dạng trong nó, và như vậy là không nguy hiểm:

/* "aa" is not dangerous, so do not display a warning */ 
printf("aa") 

Trong trường hợp đầu tiên, trình biên dịch có thể không thể nhìn thấy giá trị của chuỗi định dạng, vì vậy nó không thể xác nhận điều đó:

/* the compiler doesn't know the content of the memory region pointed by `s`, so 
    he can't determine if it's dangerous or not. Then display a warning */ 
printf(s) 
1

Disclaimer: Tôi không biết nếu điều này là lý do cho cảnh báo, nhưng nó là một lý do .

Kể từ khi số lượng đối số cho prinrf là tùy thuộc vào số lượng specifiers chuyển đổi, nó là rất phổ biến không sử dụng một chuỗi chữ như chuỗi định dạng (ví dụ, khả năng lỗi). Hơn nữa, nếu chuỗi định dạng không phải là chữ, nó sẽ xuất phát từ một nơi khác - ví dụ như người dùng hoặc tệp. Trong trường hợp này, đầu vào bị lỗi (hoặc độc hại) có thể làm hỏng chương trình của bạn, hoặc tệ hơn, mã tiêm (tức là lỗ hổng bảo mật).

Trong mọi trường hợp, nếu bạn muốn in nội dung không phải là chữ, và không có đối số định dạng, có nhiều khả năng bạn đang tìm kiếm puts, không phải là printf. (IMHO, puts là hàm không được sử dụng nhiều nhất trong thư viện C. Bạn có bao giờ nhìn thấy "hello, world" bằng cách sử dụng nó không?)

+0

Tôi đã đọc một chút về 'đặt'. – dhblah

4

Lý do là có một loạt các vấn đề bảo mật xung quanh 10 -15 năm trước do mọi người cho rằng nó được an toàn để gọi printf (s), nơi "s" đã có người dùng cung cấp đầu vào. Nhiều trình biên dịch đã thêm cảnh báo cho việc này để tránh các vấn đề. Nếu bạn muốn in ra một chuỗi, hãy sử dụng hàm puts() để thay thế.Nếu bạn không hoàn toàn chắc chắn rằng chuỗi bạn đang gửi vào printf không chứa ký tự '%', bạn nên sử dụng printf ("% s", s);

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