Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用C++;std::ostream是否具有类似printf的格式? 我正在学习C++。code>cout是std::ostream类的一个实例。 如何使用它打印格式化字符串 我仍然可以使用 Primtf>代码>,但是我想学习一个合适的C++方法,它可以利用所有C++的好处。我认为使用std::ostream应该可以做到这一点,但我找不到合适的方法。_C++_Formatting_Printf_Ostream - Fatal编程技术网

如何使用C++;std::ostream是否具有类似printf的格式? 我正在学习C++。code>cout是std::ostream类的一个实例。 如何使用它打印格式化字符串 我仍然可以使用 Primtf>代码>,但是我想学习一个合适的C++方法,它可以利用所有C++的好处。我认为使用std::ostream应该可以做到这一点,但我找不到合适的方法。

如何使用C++;std::ostream是否具有类似printf的格式? 我正在学习C++。code>cout是std::ostream类的一个实例。 如何使用它打印格式化字符串 我仍然可以使用 Primtf>代码>,但是我想学习一个合适的C++方法,它可以利用所有C++的好处。我认为使用std::ostream应该可以做到这一点,但我找不到合适的方法。,c++,formatting,printf,ostream,C++,Formatting,Printf,Ostream,使用std::ostream可以直接做的唯一一件事就是众所周知的当我需要cout的类型安全性和printf()的简单变量的快速轻松格式化时,我将两者混合在一起。这是一个丑陋的修复,但当我需要输出诸如“02/07/2014 10:05am”之类的内容以及一些更复杂的实体时,它为我完成了一些事情: #include <stdio> #include <stdarg> #include <stdlib> #include <iostream> #pra

使用
std::ostream
可以直接做的唯一一件事就是众所周知的
当我需要cout的类型安全性和printf()的简单变量的快速轻松格式化时,我将两者混合在一起。这是一个丑陋的修复,但当我需要输出诸如“02/07/2014 10:05am”之类的内容以及一些更复杂的实体时,它为我完成了一些事情:

#include <stdio>
#include <stdarg>
#include <stdlib>
#include <iostream>

#pragma hdrstop

using namespace std;


char* print(char* fmt, ...)
{
    static char buffer[80] = "";

    va_list argptr;
    va_start(argptr,fmt);

    vsprintf(buffer, fmt, argptr);

    va_end(argptr);

    return buffer;
}

#pragma argsused
int main(int argc, char* argv[])
{

cout << print("\n%06d\n%6d\n%6d\n%010.3f",1,12,123,123.456);

system("PAUSE>NUL");

return 0;

}
#包括
#包括
#包括
#包括
#布拉格语hdrstop
使用名称空间std;
字符*打印(字符*格式,…)
{
静态字符缓冲区[80]=“”;
va_列表参数;
va_启动(argptr、fmt);
vsprintf(缓冲区、fmt、argptr);
va_端(argptr);
返回缓冲区;
}
#布拉格语
int main(int argc,char*argv[])
{
库特
场宽
设置字段宽度非常简单。对于每个变量,只需在其前面加上“setw(n)”。如下所示:

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
  const int max = 12;
  const int width = 6;
  for(int row = 1; row <= max; row++) {
      for(int col = 1; col <= max; col++) {
          cout << setw(width) << row * col;
      }
      cout << endl;
  }
  return 0;
}
#包括
#包括
使用名称空间std;
int main()
{
常数int max=12;
常数int宽度=6;

对于(int row=1;row实现printf,可以使用c++11模板参数:

#include <iostream>
#include <string>

inline std::ostream & mprintf(std::ostream & ostr, const char * fstr) throw()
{
    return ostr << fstr;
}

template<typename T, typename... Args> 
std::ostream & mprintf(std::ostream & ostr, 
        const char * fstr, const T & x) throw()
{
    size_t i=0;
    char c = fstr[0];

    while (c != '%')
    {
        if(c == 0) return ostr; // string is finished
        ostr << c;
        c = fstr[++i];
    };
    c = fstr[++i];
    ostr << x;

    if(c==0) return ostr; // 

    // print the rest of the stirng
    ostr << &fstr[++i];
    return ostr;
}


template<typename T, typename... Args> 
std::ostream & mprintf(std::ostream & ostr,
        const char * fstr, const T & x, Args... args) throw()
{
    size_t i=0;
    char c = fstr[0];

    while (c != '%')
    {
        if(c == 0) return ostr; // string is finished
        ostr << c;
        c = fstr[++i];
    };
    c = fstr[++i];
    ostr << x;

    if(c==0) return ostr; // string is finished

    return mprintf(ostr, &fstr[++i], args...);
}

int main()
{
    int c = 50*6;
    double a = 34./67.;
    std::string q = "Hello!";

    // put only two arguments
    // the symbol after % does not matter at all
    mprintf(std::cout, "%f + %f = %a \n", c, a);

    // print string object: for real printf one should write q.c_str() 
    mprintf(std::cout, "message: \"%s\". \n", q);

    // the last argument will be ignored
    mprintf(std::cout, "%z + %f\n", (long)a, 12, 544 );

}
这是一个非常简单的代码,可以改进

1) 优点是它使用样本输出:

2017-12-20T16:24:47,604144+01:00 Hello, World!
代码(put_时间戳中演示了put_printf用法):


我独立写作,但得出的答案类似于user3283405


我的解决方案使用vasprintf()实现格式化,并使用运算符重载,我建议使用ostringstream而不是ostream 请参见以下示例:

#include <vector>
#include <string>
#include <iostream>
#include "CppUnitTest.h"

#define _CRT_NO_VA_START_VALIDATION

std::string format(const std::string& format, ...)
{
    va_list args;
    va_start(args, format);
    size_t len = std::vsnprintf(NULL, 0, format.c_str(), args);
    va_end(args);
    std::vector<char> vec(len + 1);
    va_start(args, format);
    std::vsnprintf(&vec[0], len + 1, format.c_str(), args);
    va_end(args);
    return &vec[0];
}
#包括
#包括
#包括
#包括“CppUnitTest.h”
#定义\u CRT\u否\u VA\u开始\u验证
标准::字符串格式(常量标准::字符串和格式,…)
{
va_列表参数;
va_开始(参数,格式);
size_t len=std::vsnprintf(NULL,0,format.c_str(),args);
va_端(args);
标准:向量向量向量(len+1);
va_开始(参数,格式);
std::vsnprintf(&vec[0],len+1,format.c_str(),args);
va_端(args);
返回&vec[0];
}
用法示例:

std::ostringstream ss;
ss << format("%s => %d", "Version", Version) << std::endl;
Logger::WriteMessage(ss.str().c_str()); // write to unit test output
std::cout << ss.str() << std::endl; // write to standard output
std::ostringstream ss;

这是我已经习惯的一个成语。希望它能帮助我:

// Hacky but idiomatic printf style syntax with c++ <<

#include <cstdlib> // for sprintf

char buf[1024]; sprintf(buf, "%d score and %d years ago", 4, 7);
cout << string(buf) <<endl;

<代码> //HACKY,但C++中的C++(20)的习惯性的PrtTf风格语法,你可以使用安全的<代码> Prtff < /C> >格式:

std::cout << std::format("The answer is {}.\n", 42);

免责声明:我是{fmt}的作者C++20
std::format

本页不是流格式的全面指南,您不应该真正需要它,因为您可以执行类似于
cout
cout的操作,字符串生成如何?也没有办法使用格式生成字符串对象?@Eonil是的。首先,您可以使用与
std::cout当你用内容填充它时(使用<代码>也可以看到一个可选的、强大的C++格式库。至少使用<代码> vSNPROTNF 以避免最明显的错误:缓冲区溢出。代码不可读。请将您的表观过敏抽象为空白和换行符。如果这个完整的答案是从教程中提取的,则应该用引用F来表示。对于我来说,这是最好的。熟悉上下文,以及C代码的简单更改,成为C++。它使用了 CSTDLIB <代码>,它将不会溢出,直到您发布代码后,右LOL最好使用像SNPRTNF这样的更安全的东西(请注意)代码> SCAFTF < /代码>。(或
std::sprintf
)函数可以在
中找到,而不是在
中找到。在我看来,这是最好的答案。使用vsnprintf获得“将要写入的字符数”,但不允许它写入任何内容是天才。我做了一个修改…我直接使用字符数组而不是向量(
char-vec)[len+1];
)。认为开销较小。然后返回字符数组(
return vec;
)GCC和可能的CLAN有注释Prtff类函数的功能。谢谢你们的工作。我一直被使用左移位操作符的概念所困扰。I.C有很多问题,C++希望解决,但他们真的把婴儿扔掉时,他们完全抛弃了格式字符串。(是的,我知道printf一直存在,但编译器本身判断您在C++中使用libc)。
#include <assert.h>
#include <chrono>
#include <iomanip>
#include <iostream>

class put_printf {
    static constexpr size_t failed = std::numeric_limits<size_t>::max(); // for any explicit error handling
    size_t stream_size; // excluding '\0'; on error set to 0 or to "failed"
    char buf_stack[2048+1]; // MAY be any size that fits on the stack (even 0), SHOULD be (just) large enough for most uses (including '\0')
    std::unique_ptr<char[]> buf_heap; // only used if the output doesn't fit in buf_stack
public:
    explicit put_printf(const char *format, ...)
            #if __GNUC__
            __attribute__ ((format (printf, 2, 3))) // most compelling reason for not using a variadic template; parameter 1 is implied "this"
            #endif
            {
        va_list args;
        va_start(args, format);
        const int res = vsnprintf(buf_stack, sizeof(buf_stack), format, args);
        va_end(args);
        if (res < 0) { // easily provoked, e.g., with "%02147483646i\n", i.e., more than INT_MAX-1 significant characters (only observed, no guarantee seen)
            stream_size = failed;
        } else if (res < sizeof(buf_stack)) { // preferred path
            stream_size = res;
        } else { // not artificially constrained
            try {
                const size_t buf_size = static_cast<size_t>(res) + 1; // avoids relying on "res < INT_MAX" (only observed, no guarantee seen)
                buf_heap.reset(new char[buf_size]); // observed to work even beyond INT_MAX=2^32-1 bytes
                va_start(args, format);
                if (vsnprintf(buf_heap.get(), buf_size, format, args) == res) stream_size = res;
                else stream_size = failed; // can't happen
                va_end(args);
            } catch (const std::bad_alloc&) { // insufficient free heap space (or an environment-specific constraint?)
                stream_size = failed;
            }
        }
    }
    friend std::ostream& operator<<(std::ostream& os, const put_printf& self) {
        if (self.stream_size == failed) {
            // (placeholder for any explicit error handling)
            return os;
        } else {
            // using write() rather than operator<<() to avoid a separate scan for '\0' or unintentional truncation at any internal '\0' character
            return os.write((self.buf_heap ? self.buf_heap.get() : self.buf_stack), self.stream_size);
        }
    }
};

class put_timestamp {
    const bool basic = false;
    const bool local = true;
public:
    friend std::ostream& operator<<(std::ostream& os, const put_timestamp& self) {
        const auto now = std::chrono::system_clock::now();
        const std::time_t now_time_t = std::chrono::system_clock::to_time_t(now);
        struct tm tm; if ((self.local ? localtime_r(&now_time_t, &tm) : gmtime_r(&now_time_t, &tm)) == nullptr) return os; // TODO: explicit error handling?
        static_assert(4 <= sizeof(int), "");
        const int microseconds = std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch() % std::chrono::seconds(1)).count();
        assert(0 <= microseconds && microseconds < 1000000); // TODO: (how) do we know?
        // TODO: doesn't "point" in "decimal_point()" imply "dot"/"full stop"/"period", unlike an obviously neutral term like "mark"/"separator"/"sign"?
        const char decimal_sign = std::use_facet<std::numpunct<char>>(os.getloc()).decimal_point() == '.' ? '.' : ','; // full stop accepted, comma preferred
        // TODO: all well and good for a locale-specific decimal sign, but couldn't the locale also upset microseconds formatting by grouping digits?
        os << std::put_time(&tm, self.basic ? "%Y%m%dT%H%M%S" : "%FT%T") << put_printf("%c%06i", decimal_sign, microseconds);
        if (! self.local) return os << "Z";
        const int tz_minutes = std::abs(static_cast<int>(tm.tm_gmtoff)) / 60;
        return os << put_printf(self.basic ? "%c%02i%02i" : "%c%02i:%02i", 0 <= tm.tm_gmtoff ? '+' : '-', tz_minutes / 60, tz_minutes % 60);
    }
};

int main() {
    // testing decimal sign
    ///std::cout.imbue(std::locale("en_GB"));
    ///std::cout.imbue(std::locale("fr_FR"));

    std::cout << put_timestamp() << " Hello, World!\n";
    #if 0
    typedef put_printf pf; // just to demo local abbreviation
    std::cout << "1: " << pf("%02147483646i\n"  , 1     ) << std::endl; // res < 0
    std::cout << "2: " << pf("%02147483643i%i\n", 1, 100) << std::endl; // res < 0
    std::cout << "3: " << pf("%02147483643i%i\n", 1,  10) << std::endl; // works
    std::cout << "4: " << pf("%02147483646i"    , 1     ) << std::endl; // works
    #endif
    return 0;
}
// Reasons for the name "put_printf" (and not "putf" after all):
// - put_printf is self-documenting, while using the naming pattern also seen in std::put_time;
// - it is not clear whether the proposed std::putf would support exactly the same format syntax;
// - it has a niche purpose, so a longer name is not an objection, and for frequent local uses
//     it is easy enough to declare an even shorter "typedef put_printf pf;" or so.
// Evaluation of delegating to vsnprintf() with intermediate buffer:
// (+) identical result without implementation and/or maintenance issues,
// (?) succeeds or fails as a whole, no output of successful prefix before point of failure
// (-) (total output size limited to INT_MAX-1)
// (-) overhead (TODO: optimal buf_stack size considering cache and VM page locality?)
// Error handling (an STL design problem?):
// - std::cout.setstate(std::ios_base::failbit) discards further std::cout output (stdout still works),
//     so, to be aware of an error in business logic yet keep on trucking in diagnostics,
//     should there be separate classes, or a possibility to plug in an error handler, or what?
// - should the basic or default error handling print a diagnostic message? throw an exception?
// TODO: could a function "int ostream_printf(std::ostream& os, const char *format, ...)"
//           first try to write directly into os.rdbuf() before using buf_stack and buf_heap,
//           and would that significantly improve performance or not?
std::cout << putf(const char *format, ...); //Same format as C printf(3)
#define _GNU_SOURCE
#include <cstdarg>
#include <iostream>
#include <cstdio>

struct putf_r{
        char *s;
};

putf_r putf(const char *fmt, ...){
        va_list ap;
        va_start(ap, fmt);
        putf_r a;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
        vasprintf(&a.s, fmt, ap);
#pragma GCC diagnostic pop
        va_end(ap);
        return a;
}

std::ostream& operator<<(std::ostream& os, putf_r a){
        os<<a.s;
        free(a.s);
        return os;
}

int main(){
        std::cout << putf("%3d\n", 23) << putf("%a\n", 256.);
}
#include <vector>
#include <string>
#include <iostream>
#include "CppUnitTest.h"

#define _CRT_NO_VA_START_VALIDATION

std::string format(const std::string& format, ...)
{
    va_list args;
    va_start(args, format);
    size_t len = std::vsnprintf(NULL, 0, format.c_str(), args);
    va_end(args);
    std::vector<char> vec(len + 1);
    va_start(args, format);
    std::vsnprintf(&vec[0], len + 1, format.c_str(), args);
    va_end(args);
    return &vec[0];
}
std::ostringstream ss;
ss << format("%s => %d", "Version", Version) << std::endl;
Logger::WriteMessage(ss.str().c_str()); // write to unit test output
std::cout << ss.str() << std::endl; // write to standard output
// Hacky but idiomatic printf style syntax with c++ <<

#include <cstdlib> // for sprintf

char buf[1024]; sprintf(buf, "%d score and %d years ago", 4, 7);
cout << string(buf) <<endl;
std::cout << std::format("The answer is {}.\n", 42);
fmt::print("The answer is {}.\n", 42);