2011-01-24 14 views
11

thể trùng lặp:
Should I use printf in my C++ code?printf vs std :: cout

Nếu tôi chỉ muốn in một string trên màn hình, tôi có thể làm điều đó bằng hai cách:

printf("abc"); 

std::cout << "abc" << std::endl; 

Trường hợp là, và trong các ví dụ được hiển thị ở trên, có lợi thế khi sử dụng printf trên std::cout hoặc ngược lại?

+6

Nếu bạn đang viết mã C++ thì bạn nên nói chung thích các thành ngữ và thư viện C++. –

+0

Nó phụ thuộc vào ngôn ngữ nào bạn đang viết chương trình của bạn hoặc C hoặc C++. Cả hai phương pháp này đều có ngôn ngữ khác nhau, do đó bạn không thể so sánh trực tiếp. –

+1

@Paul R. Cảm ơn bạn đã trả lời. Vì vậy, không phải là "printf()" sau đó được coi là một thành ngữ C++? –

Trả lời

1

Hai ví dụ đó làm những việc khác nhau. Sau đó sẽ thêm một ký tự dòng mới và đầu ra tuôn ra (kết quả của std::endl). std::cout cũng chậm hơn. Ngoài ra, printfstd::cout cũng đạt được điều tương tự và bạn có thể chọn bất cứ điều gì bạn thích. Như một vấn đề ưu tiên, tôi muốn sử dụng std::cout trong mã C++. Nó dễ đọc hơn và an toàn hơn.

Xem this article nếu bạn cần định dạng đầu ra bằng cách sử dụng std::cout.

+0

Cảm ơn bạn đã trả lời. Tại sao "std :: cout" như bạn đề cập đến chậm hơn? Điều gì có nghĩa là "chậm" ở đây? Ví dụ về những gì? Cảm ơn. –

+0

@aali Sẽ chậm hơn vì các lý do khác giải thích chi tiết giải thích: nó có nhiều nội dung hơn. Nó rất phụ thuộc vào trình biên dịch của bạn, nhưng tôi đã thấy các phiên bản cũ của GCC chậm hơn 10 lần trong mọi trường hợp. – marcog

+0

Với g ++ 4.x, trong testcase tôi cam kết, ostreams nhanh như printfs, nếu bạn 'sync_with_stdio (false)'. –

0

Nói chung, bạn nên chọn cout vì nó an toàn hơn nhiều và chung chung hơn. printf không an toàn kiểu, cũng không phải là chung chung. Lý do duy nhất bạn có thể ủng hộ printf là tốc độ - từ bộ nhớ, printf nhanh gấp nhiều lần so với cout.

+0

Cảm ơn bạn đã trả lời. Tôi thấy rằng "printf()" cho phép định dạng, không "cout" cung cấp rằng quá? –

+0

Ý của bạn là gì khi bạn nói: "printf không an toàn, cũng không phải là chung. Lý do duy nhất bạn có thể ưu tiên printf là tốc độ - từ bộ nhớ, printf nhanh gấp nhiều lần so với cout". Bạn có thể làm rõ điều đó một chút không. Cảm ơn. –

+0

@aali: cout cũng cung cấp định dạng đầu ra. –

26

Trong khi cout là C++ cách thích hợp, tôi tin rằng một số người và các công ty (bao gồm Google) tiếp tục sử dụng printf trong C++ vì nó là dễ dàng hơn nhiều việc phải làm đầu ra định dạng với printf hơn với cout.

Đây là một ví dụ thú vị mà tôi đã tìm thấy here.

Hãy so sánh:

printf("%-20s %-20s %5s\n" , "Name" , "Surname" , "Id"); 

cout << setw(-20) << "Name" << setw(20) << "Surname" << setw(5) << "Id" << endl; 
+3

+1, bạn đã tuyên bố một lợi thế của printf vì vậy trông giống như một câu trả lời hợp lệ cho tôi. – CashCow

+3

Một ví dụ cho thấy rằng một dòng mã nhỏ hơn không phải lúc nào cũng dễ đọc hơn. Phiên bản 'std :: cout' tuyên bố rõ ràng những gì nó đang làm trên mỗi bước của con đường. 'printf' có chuỗi định dạng khó hiểu. –

+2

Đó là sự thật, nhưng một khi bạn quen với nó, có thể lập luận rằng printf dễ sử dụng hơn trong cả hai. Cá nhân, tôi đã luôn luôn tìm thấy định dạng dòng để rất clunky. – dandan78

14

printf và bạn bè có liên quan của nó là C chức năng. Chúng hoạt động trong C++, nhưng không có kiểu an toàn của C++ std::ostreams. Vấn đề có thể phát sinh trong các chương trình sử dụng các hàm printf để định dạng đầu ra dựa trên đầu vào của người dùng (hoặc thậm chí đầu vào từ một tệp). Ví dụ:

int main() 
{ 
    char[] a = {'1', '2', '3', '4'}; // a string that isn't 0-terminated 
    int i = 50; 
    printf("%s", a); // will continue printing characters until a 0 is found in memory 
    printf("%s", i); // will attempt to print a string, but this is actually an integer 
} 

C++ có nhiều loại an toàn hơn (và lớp std::string) để giúp ngăn chặn các vấn đề như thế này.

+1

@Zac Howland. Cảm ơn vì đã trả lời. Tại sao không phải là chuỗi bạn khai báo trên 0 chấm dứt? Không phải là chuỗi luôn luôn 0 chấm dứt? Và, bạn có ý nghĩa gì bởi "an toàn loại"? Cảm ơn. –

+0

Tôi không nghĩ rằng điều này rất phù hợp khi in một chuỗi chữ. – marcog

+3

@ aali Ông định nghĩa một mảng ký tự, những thứ chỉ xảy ra để có thể được hiểu là chuỗi trong C, nó sẽ không tự động thêm một số không-byte vào cuối mảng. –

2

Thực tế cho ví dụ cụ thể của bạn, bạn nên hỏi cái nào là thích hợp hơn, đặt hoặc cout. printf in văn bản được định dạng nhưng bạn chỉ cần xuất văn bản thuần túy vào bảng điều khiển.

Để sử dụng chung, luồng (iostream, trong đó cout là một phần) có thể mở rộng hơn (bạn có thể in các loại của riêng mình), và chung chung hơn ở đó bạn có thể tạo các chức năng để in cho bất kỳ loại luồng nào , không chỉ bàn điều khiển (hoặc đầu ra được chuyển hướng). Bạn có thể tạo hành vi dòng chung chung với printf quá sử dụng fprintf mà lấy một FILE * như một FILE * thường không phải là một tập tin thực sự, nhưng điều này là khó khăn hơn.

Luồng đang "an toàn" khi bạn quá tải với loại bạn đang in. printf không an toàn với việc sử dụng dấu ba chấm để bạn có thể nhận được kết quả không xác định nếu bạn đặt các kiểu tham số sai trong đó không khớp với chuỗi định dạng, nhưng trình biên dịch sẽ không phàn nàn. Bạn thậm chí có thể nhận được một hành vi seg-fault/undefined (nhưng bạn có thể với cout nếu được sử dụng không chính xác) nếu bạn bỏ lỡ một tham số hoặc vượt qua trong một xấu (ví dụ như một số cho% s và nó xử lý nó như một con trỏ anyway).

printf có một số lợi thế: bạn có thể tạo chuỗi định dạng rồi sử dụng lại chuỗi định dạng cho dữ liệu khác nhau, ngay cả khi dữ liệu đó không có cấu trúc và sử dụng thao tác định dạng cho một biến không "gắn" định dạng đó để sử dụng thêm vì bạn chỉ định định dạng cho mỗi biến. printf còn được gọi là threadsafe trong khi cout thực sự thì không.

tăng cường đã kết hợp những lợi thế của từng loại với thư viện định dạng tăng ::.

+0

+1 để đề cập đến tăng :: định dạng – GrahamS

+0

+1 "_bạn nên đã hỏi cái nào là thích hợp hơn,' đặt' hoặc 'cout'_". tôi đang googling để cố gắng tìm những người gọi những người nội bộ, puts() có một cuộc gọi 'cout' trong nó? – LoneXcoder

2

Tôi đấu tranh với chính câu hỏi này. printf nói chung dễ sử dụng hơn cho việc in định dạng, nhưng cơ sở iostreams trong C++ có lợi thế lớn là bạn có thể tạo các trình định dạng tùy chỉnh cho các đối tượng. Tôi kết thúc bằng cách sử dụng cả hai người trong số họ trong mã của tôi khi cần thiết.

Vấn đề với việc sử dụng cả hai và trộn chúng là các bộ đệm đầu ra được sử dụng bởi printf và cout không giống nhau, vì vậy trừ khi bạn chạy đầu ra không được lọc hoặc rõ ràng, bạn có thể kết thúc với đầu ra bị hỏng.

Phản đối chính của tôi đối với C++ là không có cơ sở định dạng đầu ra nhanh tương tự như printf, vì vậy không có cách nào để dễ dàng kiểm soát đầu ra cho định dạng số nguyên, hex và dấu phẩy động.

Java có cùng vấn đề này; ngôn ngữ đã kết thúc bằng việc nhận được printf.

Wikipedia có thảo luận tốt về vấn đề này tại http://en.wikipedia.org/wiki/Printf#C.2B.2B_alternatives_to_sprintf_for_numeric_conversion.

2

printf đã được mượn từ C và có một số hạn chế. Giới hạn được đề cập phổ biến nhất của printf là loại an toàn, vì nó dựa trên lập trình viên để khớp chính xác chuỗi định dạng với các đối số. Giới hạn thứ hai đến từ môi trường varargs là bạn không thể mở rộng hành vi với các kiểu do người dùng định nghĩa. Các printf biết làm thế nào để in một tập hợp các loại, và đó là tất cả những gì bạn sẽ nhận được ra khỏi nó. Tuy nhiên, nó cho một vài điều mà nó có thể được sử dụng cho, nó là nhanh hơn và đơn giản hơn để định dạng chuỗi với printf hơn với C++ suối.

Trong khi hầu hết các trình biên dịch hiện đại, có thể giải quyết giới hạn an toàn loại và ít nhất cung cấp cảnh báo (trình biên dịch có thể phân tích chuỗi định dạng và kiểm tra các đối số được cung cấp trong cuộc gọi), giới hạn thứ hai không thể khắc phục được. Ngay cả trong trường hợp đầu tiên, có những thứ mà trình biên dịch có thể không thực sự giúp đỡ, như kiểm tra cho null chấm dứt - nhưng sau đó một lần nữa, cùng một vấn đề đi với std::cout nếu bạn sử dụng nó để in cùng một mảng. Ở phía bên kia, các dòng (bao gồm std::cout) có thể được mở rộng để xử lý các loại do người dùng xác định bằng phương tiện quá tải std::ostream& operator<<(std::ostream&, type const &) cho bất kỳ người dùng đã xác định nào type. Họ là loại an toàn của mình - nếu bạn vượt qua trong một loại mà không có quá tải operator<< trình biên dịch sẽ khiếu nại. Họ là, mặt khác, cồng kềnh hơn để sản xuất định dạng đầu ra.

Vì vậy, bạn nên sử dụng những gì? Nói chung tôi thích sử dụng các dòng, vì quá tải operator<< cho các loại của riêng tôi là đơn giản và chúng có thể được sử dụng thống nhất với tất cả các loại.