Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/160.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.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++ 从自定义printf函数返回常量char*_C++_C_Printf_Variadic Functions - Fatal编程技术网

C++ 从自定义printf函数返回常量char*

C++ 从自定义printf函数返回常量char*,c++,c,printf,variadic-functions,C++,C,Printf,Variadic Functions,我已经编写了一个自定义打印函数。我的问题是我需要返回一个const char*,因为它必须在另一个函数中使用。我根本不知道该怎么办 另一个函数(const char*text/*Here*/,unsigned\uu int32值,unsigned\uu int64 bigVal) 我知道下面的示例不能正常工作。这就是我到目前为止所尝试的 const char* CatchMessage (const char *message, ...) { va_list args; va_

我已经编写了一个自定义打印函数。我的问题是我需要返回一个
const char*
,因为它必须在另一个函数中使用。我根本不知道该怎么办

另一个函数(const char*text/*Here*/,unsigned\uu int32值,unsigned\uu int64 bigVal)

我知道下面的示例不能正常工作。这就是我到目前为止所尝试的

const char* CatchMessage (const char *message, ...)
{
    va_list  args;
    va_start (args, message);
    /*?*/
    va_end   (args);
    return message;
}
我还只能在cmd中获得正确的输出,但实际上我需要它作为返回值

void CatchMessage (const char *message, ...)
{
    va_list  args;
    va_start (args, message);
    vfprintf (stdout, message, args);
    va_end   (args);
}
电话:

应返回:

"Some Input stuff and 12 equals to 6"
我一直未能找到解决办法。任何帮助都将不胜感激


问:如何让这个
CatchMessage
函数返回格式正确的
const char*

听起来
CatchMessage
应该将指针指向一个char缓冲区(及其大小)并放入该缓冲区

char* CatchMessage (size_t size, const char *message, ...)
{
    char result[size];
    va_list  args;
    va_start (args, message);
    vsprintf (result, message, args);
    va_end   (args);
    return result;
}
请参阅以供参考


<>和GLGLL:如果您想使用干净的方式,使用<代码> VSNPRETCF(结果、大小、消息、ARG)< /Calp>

> P>因为您使用C++(至少根据问题的标签)为什么不返回字符串在<代码> STD::String ?/P> < P>返回一个问题(<代码> const )
char*
就是你必须在某个地方有一个缓冲区

有几种方法可以实现这一点:

  • 调用方必须提供该缓冲区
  • 您必须
    malloc()
    it
  • 函数本身作为一个
    静态
    缓冲区,但这会使它不可重入-这对多线程等不利
  • 广告1:

    打电话给

    char buffer[500];
    CatchMessage(buffer, sizeof buffer, "Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
    anotherfunction(buffer, ...)
    
    char * buffer = CatchMessage(buffer, sizeof buffer, "Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
    if (!buffer) { /* error handling: no memory! */ }
    anotherfunction(buffer, ...)
    free(buffer); // important for avoiding memory leaks
    
    char * buffer = CatchMessage(buffer, sizeof buffer, "Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
    anotherfunction(buffer, ...)
    
    广告2:

    广告3:

    打电话给

    char buffer[500];
    CatchMessage(buffer, sizeof buffer, "Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
    anotherfunction(buffer, ...)
    
    char * buffer = CatchMessage(buffer, sizeof buffer, "Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
    if (!buffer) { /* error handling: no memory! */ }
    anotherfunction(buffer, ...)
    free(buffer); // important for avoiding memory leaks
    
    char * buffer = CatchMessage(buffer, sizeof buffer, "Some Input %s and %d equals to %d", randString, randNumber, secRandNumber);
    anotherfunction(buffer, ...)
    
    没有其他选择,尤其是没有定义

    char result[500];
    

    在函数中,然后返回:此数组位于堆栈上,并在返回后立即释放。调用者无法安全地访问它;它的内容只是未定义。

    如果您不关心重新进入,您可以返回指向静态缓冲区的指针:

    #define MESSAGE_MAX 1024
    
    const char *
    CatchMessage (const char *message, ...)
    {
        static buffer[MESSAGE_MAX];
        va_list  args;
        va_start (args, message);
        vsnprintf (buffer, MESSAGE_MAX, message, args);
        va_end   (args);
        return buffer;
    }
    
    注:

  • 此实现不是线程安全的。如果您关心线程安全,请使用线程本地存储而不是静态缓冲区

  • 此实现具有消息长度的硬编码上限。如果不需要这样做,并且您的编译器是C99兼容的,那么您可以使用
    NULL
    调用第一个
    vsprintf
    ,作为第一个参数来了解结果字符串长度,然后分配该端的缓冲区


  • 在C++中,变量的使用是不好的,因为有一定的强调类型安全性(和内存安全性)。因此,您可能希望提出一个实际上是类型安全的版本(是的,这是可能的),同时还提出了一个类似的接口:

    template <typename H, typename... Args>
    void format(std::ostream& out,
                char const* format,
                size_t len,
                H const& head,
                Args const&... args);
    
    // Variations with 'char const (&)[N]' and 'std::string' formats
    // as well as variations returning directly a 'std::string'.
    

    在一般情况下,它稍微有点毛茸茸的,因为您需要解析修饰符等等。。。但是,对于生产就绪的实现,我建议看一下Boost.Format。

    我建议检查您的系统是否有
    vasprintf()
    vs[n]printf()
    (后者可以调用两次,一次使用空缓冲区获取输出长度,然后在缓冲区上再次调用
    malloc
    /
    new
    )。。。您的客户端代码需要负责释放内存。但是,这有什么意义呢?你有没有考虑过
    boost::format
    std::string
    ?当然没有。
    结果
    指向哪里?为什么
    vsprintf()
    而不是
    vsnprintf()
    ?对不起,我的坏:)忘记将void更改为char*。为什么是vsprintf?因为如果他阅读我链接的文档,他会自己找到安全的方法;)如果生成的字符串超过500个字符呢?不,你不能-那就太晚了,代码已经编译好了。使用
    vsnprintf()
    有什么问题?然后所有的问题都消失了。不,它们不是:你的数组是如何生存的?它也被标记为C++ +ToTuna:最后我听说它被推荐在C++中使用RAII;真正的问题在于,最佳答案很大程度上取决于你是否想要C或C++解决方案。当然,C++中可以使用C解决方案;但是为什么要标记它C++呢?它什么也没有带来。就我而言,任何C++标记的问题都要用C++ 11的全部强度(最好是实践)来回答,除非有OP的特殊要求。我想有人用C标记了一个问题,需要C解决方案。如果他们把这两者都贴上标签,我怀疑他们是在混合环境中使用的。也许它可以是使用C++方法的代码,但是接口必须匹配C。在这种情况下,在中间代码中使用STD::string是有效的。但他说他需要一个常量字符,很可能他不能改变这个要求。告诉他返回一个std::string不会有多大帮助。他需要用一个
    char const*
    调用另一个函数
    ,但是
    std::string
    提供了这一点(使用
    c_str
    );不清楚的是,所说的
    另一个功能是否拥有所有权。如果没有:
    另一个函数(格式(…).c_str(),…)完全匹配,C++中的临时生命周期规则保证<>代码> STD::String  >在代码> > Actudio< <代码>调用结束后,将被销毁,这是完美的。老实说,这个问题确实是在指定的:(我把它标记成C和C++,因为我对两种解决方案都是开放的。这不是一个很大的问题来解决它们之间的差异。我知道STD::String将在正常情况下工作,但是在这种情况下我不能使用它。(无论如何谢谢。+ 1)
    
    template <typename H, typename... Args>
    void format(std::ostream& out,
                char const* format,
                size_t len,
                H const& head,
                Args const&... args);
    
    // Variations with 'char const (&)[N]' and 'std::string' formats
    // as well as variations returning directly a 'std::string'.
    
    inline void format_string(std::ostream& out, char const* const* c) { out << *c; }
    inline void format_string(std::ostream& out, std::string const* s) { out << *s; }
    inline void format_string(std::ostream& out, void const*); // will throw
    
    template <typename Integral, typename = enable_integral<Integral>::type>
    inline void format_integral(std::ostream& out, Integral const* i) { out << *i; }
    inline void format_integral(std::ostream& out, void const*); // will throw
    
    inline size_t format_consume(std::ostream& out,
                                 char const* const format,
                                 size_t const length)
    {
        char const* end = format + length;
        char const* current = format;
    
        do {
            // 1. Find first "format identifier", output stuff in-between
            char const* perc = std::find(current, end, '%');
    
            if (perc != current) { out.write(current, perc - current); }
    
            current = perc;
    
            // 2. %% is % escaped by %, so output it directly
            while (*current == '%' and *(current + 1) == '%') {
                out.put('%');
                current += 2;
            }
        } while (current != end and *current != '%');
    
        // 3. Return number of characters of format parameter consumed
        return current - format;
    } // format_consume
    
    inline void format(std::ostream& out, char const* format, size_t len) {
         size_t const consumed = format_consume(out, format, len);
    
         if (consumed != len) { throw std::runtime_exception("Missing arguments"); }
    } // format
    
    template <typename H, typename typename... Args>
    void format(std::ostream& out,
                char const* format,
                size_t len,
                H const& head,
                Args const&... args)
    {
         size_t const consumed = format_consume(out, format, len);
    
         if (consumed == len) { throw std::runtime_exception("Extraneous arguments"); }
    
         format += consumed;
         len -= consumed;
    
         assert(*format == '%');
    
         switch(*(format+1)) {
         case 's': format_string(out, &head); break;
         case 'd': format_integral(out, &head); break;
         default: throw std::runtime_exception("Invalid specifier");
         }
    
         format(out, format+2, len-2, args...);
    } // format