C ++ tương đương với sprintf?


82

Tôi biết đó std::coutlà C ++ tương đương với printf.

C ++ tương đương là sprintfgì?

Câu trả lời:


66

std::ostringstream

Thí dụ:

#include <iostream>
#include <sstream> // for ostringstream
#include <string>

int main()
{
  std::string name = "nemo";
  int age = 1000;
  std::ostringstream out;  
  out << "name: " << name << ", age: " << age;
  std::cout << out.str() << '\n';
  return 0;
}

Đầu ra:

name: nemo, age: 1000

3
Tôi không nghĩ rằng sprintf viết cho stdout. Tôi sẽ xóa câu lệnh chèn ở trên.
Raffi Khatchadourian

78
Làm thế nào là điều này thậm chí từ xa tương tự như sprintf (...)? Bạn không thể định dạng dữ liệu một cách tùy tiện, bạn phải dựa vào kiểu được biết khi bạn đưa nó vào luồng bằng <<toán tử.
Andon M. Coleman

Tôi cần đồng ý với @ AndonM.Coleman về vấn đề này. Đây không thực sự là một sự thay thế chạy nước rút. Điều này sẽ giống như vậy, nhưng đây là Qt.
lpapp

như @vinkris nói trong câu trả lời của mình, iomanip đạt được định dạng. Thay vì in ra stdoit, tôi sẽ nói "result = out.str ()".
Dmitri

sprintf / snprintf cho phép định dạng và in ra một mảng ký tự do người dùng cấp phát, có thể nằm trên ngăn xếp. Trong trường hợp snprintf (), nó đảm bảo không có chạy quá mức. Ở đây chúng tôi đang cấp phát bộ nhớ nhiều lần và người gọi không có quyền truy cập trực tiếp vào bộ nhớ đó. Phải chuyển đổi thành một chuỗi để có được đầu ra. Một std :: ostream với std :: streambuf tùy chỉnh, chiếm bộ đệm của người dùng sẽ phù hợp hơn - tất nhiên việc xây dựng / phá hủy ostream / streambuf sẽ tăng hiệu quả hơn.
MGH

34

Cập nhật, tháng 8 năm 2019:

Có vẻ như C ++ 20 sẽ có std::format. Triển khai tham chiếu là {fmt} . Nếu printf()bây giờ bạn đang tìm kiếm một giải pháp thay thế thì đây sẽ trở thành cách tiếp cận “tiêu chuẩn” mới và rất đáng xem xét.

Nguyên:

Sử dụng Boost.Format . Nó có printfcú pháp giống, kiểu an toàn, std::stringkết quả và rất nhiều thứ tiện lợi khác. Bạn sẽ không quay trở lại.


14
... trừ khi bạn đang quan tâm về kích thước của thực thi .. của bạn: P
pradyunsg

Điều này sẽ có bao nhiêu tác động? Phụ thuộc Boost sẽ chỉ là tiêu đề, không có liên kết, đúng không?
Ken Williams,

1
@KenWilliams Có, Boost.Format chỉ là tiêu đề. Một bài kiểm tra đơn giản "hello, world" trên máy Mac của tôi tăng từ 10kB lên 78kB. Trong một dự án thực, kích thước tăng thêm sẽ được phân bổ cho các đơn vị biên dịch (đưa ra các tùy chọn trình liên kết phù hợp), và sự an toàn kiểu mang lại những lợi ích khác.
janm

17

sprintf hoạt động tốt trong C ++.


4
Tôi nghĩ OP có nghĩa là STL hơn là C ++.
Jean-Michaël Celerier

4
sprintf yêu cầu bạn cấp phát bộ đệm ký tự. Tôi muốn một cái gì đó giống như phương thức "append" của "std :: string" cho phép tôi thêm dữ liệu được định dạng và quan tâm đến việc phân bổ hậu trường.
Victor Eijkhout

7

Bạn có thể sử dụng tệp tiêu đề iomanip để định dạng luồng đầu ra. Kiểm tra này !


Tại sao ai đó lại phản đối điều này? Iomanip không phải là cách thuần C ++ để đạt được định dạng trong luồng sao? Tôi nghĩ mục tiêu ở đây là tránh lưu trữ dữ liệu trong chuỗi kiểu C, điều này đạt được với iomanip.
Dmitri

7

Đây là một chức năng hay cho c ++ sprintf. Các luồng có thể trở nên xấu đi nếu bạn sử dụng chúng quá nhiều.

std::string string_format(const std::string &fmt, ...) {
    int size=100;
    std::string str;
    va_list ap;

    while (1) {
        str.resize(size);
        va_start(ap, fmt);
        int n = vsnprintf(&str[0], size, fmt.c_str(), ap);
        va_end(ap);
   
        if (n > -1 && n < size) {
            str.resize(n); // Make sure there are no trailing zero char
            return str;
        }
        if (n > -1)
            size = n + 1;
        else
            size *= 2;
    }
}

Trong C ++ 11 trở lên, std :: string được đảm bảo sử dụng bộ nhớ liền kề có kết thúc bằng '\0', vì vậy việc truyền nó để char *sử dụng là hợp pháp &str[0].

Nó đã được chỉ ra rằng các đối số khác nhau không được cho là tuân theo tham chiếu truyền và c ++ tốt về việc không sao chép các chuỗi nếu nó không cần thiết. Trong trường hợp đó, điều này sẽ sửa chữa nó.

std::string string_format(std::string fmt, ...) {

Giải pháp rất hay! Tôi đã điều chỉnh nó ở đây: stackoverflow.com/a/3742999/15161 để phù hợp hơn với sprintf-usage.
slashmais 27/12/12

10
Bất hợp pháp, mặc dù: (char*) str.c_str()bỏ đi const.
MSalters

cũng có vấn đề tràn bộ đệm ẩn
Barney Szabolcs

@MSalters Đúng. Có một cách hợp pháp để làm điều đó trong C ++ 11.
whitequark

@whitequark: Vui lòng thêm câu trả lời đó vào. Trên Stack Overflow, câu hỏi hay vẫn mở để cho phép các câu trả lời mới.
MSalters

0

Sử dụng chuỗi ký tự để đạt được hiệu quả tương tự. Ngoài ra, bạn có thể bao gồm <cstdio>và vẫn sử dụng snprintf.


0

Tùy thuộc vào chính xác những gì bạn định nhập sprintf(), std::to_string()có thể hữu ích và dễ thành ngữ hơn các tùy chọn khác:

void say(const std::string& message) {
 // ...
}

int main() {
  say(std::to_string(5));
  say("Which is to say " + std::to_string(5) + " words");
}

Ưu điểm chính của std::to_string()IMHO là nó có thể được mở rộng dễ dàng để hỗ trợ các kiểu bổ sung mà sprintf()bạn thậm chí không thể mơ đến việc xâu chuỗi - giống như Object.toString()phương pháp của Java .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.