Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.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++ snprintf:相同的代码-不同g++;编译程序_C++_C++11_G++_Printf - Fatal编程技术网

C++ snprintf:相同的代码-不同g++;编译程序

C++ snprintf:相同的代码-不同g++;编译程序,c++,c++11,g++,printf,C++,C++11,G++,Printf,我知道以前可能有人问过这个问题,但没有回答我在下面发布的问题。我试图弄清楚为什么下面的代码会给出错误(在其他版本的GCC中,会给出警告),特别是如何解决这个问题?我是一个经验丰富的C++程序员,但有时你确实需要寻求帮助。感谢您的帮助 [错误]:无法通过传递非普通可复制类型“class std::basic_string”的对象 /// USE THE MACRO BELOW TO LOG A FORMATTED STRING (usage is exactly like printf(...)

我知道以前可能有人问过这个问题,但没有回答我在下面发布的问题。我试图弄清楚为什么下面的代码会给出错误(在其他版本的GCC中,会给出警告),特别是如何解决这个问题?我是一个经验丰富的C++程序员,但有时你确实需要寻求帮助。感谢您的帮助

[错误]:无法通过传递非普通可复制类型“class std::basic_string”的对象

/// USE THE MACRO BELOW TO LOG A FORMATTED STRING (usage is exactly like printf(...) [ SEE HEADER FILE - TEMPLATE FUNCTION user_log_fmt(...) ]
#define LOG_TRACE_FMT(...)  Logger::getInstance()->user_log_fmt(LOG_LEVEL_TRACE,   __PRETTY_FUNCTION__, __FUNCTION__, __VA_ARGS__)

void main()
{   
    std::string linkName = getLinkName();

    // THIS IS THE CALL THAT LEADS TO THE ERROR AT COMPILE-TIME
    LOG_TRACE_FMT("\nLink-name: %s, Sent packet: SYS: %d, COMP: %d, LEN: %d, MSG ID: %d\n", linkName, msg->sysid, msg->compid, msg->len, msg->msgid);
}
///
/// Part of logger class (combines strings with argument for formatting) 
///
template <typename ... Args>
void user_log_fmt(LOG_LEVEL level,  std::string pretty_func, std::string func_name, std::string str_format, Args ... args)
{
    if (m_LogLevel < level)
        return;

    std::string formatted_data = utils::Utils::string_format(str_format, args...);
    // Do something with the formatted string.. 
}

///
/// Part of Utils library. This method does a printf type formatting.
///
template<typename ... Args>
static std::string string_format( const std::string& format, Args ... args )
{
    size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
    std::unique_ptr<char[]> buf( new char[ size ] );
    snprintf( buf.get(), size, format.c_str(), args ... );
    return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
}
///使用下面的宏记录格式化字符串(用法与printf(…)完全相同[请参阅头文件-模板函数user_LOG_fmt(…)]
#定义日志跟踪FMT(…)记录器::getInstance()->用户日志FMT(日志级别跟踪、函数、函数、参数)
void main()
{   
std::string linkName=getLinkName();
//这是导致编译时出错的调用
日志跟踪(“\n链接名称:%s,发送的数据包:SYS:%d,COMP:%d,LEN:%d,MSG ID:%d\n”,链接名称,MSG->sysid,MSG->compid,MSG->LEN,MSG->msgid);
}
///
///logger类的一部分(将字符串与用于格式化的参数组合在一起)
///
模板
无效用户日志fmt(日志级别,标准::字符串函数,标准::字符串函数名称,标准::字符串str格式,Args…Args)
{
如果(m_LogLevel
错误与上面的snprintf语句有关

g++(Ubuntu 5.4.0-6ubuntu1~16.04.4)5.4.0 20160609上的警告:

警告:格式不是字符串文字,也没有格式参数[-Wformat security] size\u t size=snprintf(nullptr,0,format.c_str(),args…)+1;' ^

g++(Raspbian 4.9.2-10)4.9.2上的错误

错误:无法通过“…”传递非普通可复制类型“class std::basic_string”的对象 size_t size=snprintf(nullptr,0,format.c_str(),args…)+1

注意:我希望理解并解决这个问题,但不提供编译器标志设置。我理解这可能与C有关 与C++的兼容性
谢谢!

我找到了这个歧义的答案。谢谢@PaulMcKenzie指出。这是我看到的解决方案,它使用了任何编译器标志,例如“-Wno格式安全性”。Pi上没有更多错误,Ubuntu g++上也没有错误

void main()
{   
    std::string linkName = getLinkName();

    // THIS IS THE CALL THAT LEADS TO THE ERROR AT COMPILE-TIME
    LOG_TRACE_FMT("\nLink-name: %s, Sent packet: SYS: %d, COMP: %d, LEN: %d, MSG ID: %d\n", linkName.c_str(), msg->sysid, msg->compid, msg->len, msg->msgid);
}
捕获操作是执行linkName.c_str()(c样式字符串),而不是将std::string作为参数传递。这很棘手


我找到了这个模糊性的答案。感谢@PaulMcKenzie指出。这是我看到的解决方案,它使用了任何编译器标志,例如“-Wno格式安全性”。Pi上没有更多错误,Ubuntu g++上也没有错误

void main()
{   
    std::string linkName = getLinkName();

    // THIS IS THE CALL THAT LEADS TO THE ERROR AT COMPILE-TIME
    LOG_TRACE_FMT("\nLink-name: %s, Sent packet: SYS: %d, COMP: %d, LEN: %d, MSG ID: %d\n", linkName.c_str(), msg->sysid, msg->compid, msg->len, msg->msgid);
}
捕获操作是执行linkName.c_str()(c样式字符串),而不是将std::string作为参数传递。这很棘手


我不知道是什么导致了你的问题,但我不知道你从使用模板函数中得到了什么好处。你可以使用好的老式varargs来解决这个问题

我想说的是,编写varargs函数的黄金法则是编写一个采用
va_list
的函数。您的编辑非常清楚地说明了这一点——您通常会从另一个varargs函数调用varags函数

#include <stdarg.h>  // varargs support

static std::string string_vformat( const std::string& format, va_list args)
{
    va_list args_copy;
    va_copy(args,args_copy);  // Copy args before we use it.
                              // +1 is extra space for '\0'
    const size_t size = vsnprintf( nullptr, 0, format.c_str(), args_copy ) + 1; 
    va_end(args_copy);        // Release args_copy.
    std::unique_ptr<char[]> buf( new char[ size ] );
    vsnprintf( buf.get(), size, format.c_str(), args );
    // Caller must va_end(args);
           // We don't want the '\0' inside
    return std::string( buf.get(), buf.get() + size - 1 );
}

static std::string string_format( const std::string& format, ... )
{
    va_list args;
    va_start(format, args);
    const auto result = string_vformat(format, args);
    va_end(args);
    return result;
}

void user_log_fmt(LOG_LEVEL level,  std::string pretty_func, std::string func_name,
                                    std::string str_format, ... )
{
    if (m_LogLevel < level)
        return;

    va_list args;
    va_start(format, args);
    std::string formatted_data = utils::Utils::string_vformat(str_format, args);
    // Do something with the formatted string.. 
}
然后你可以声明:

 void user_log_fmt(LOG_LEVEL level, std::string pretty_func, std::string func_name,
                  std::string str_format, ... ) PRINTFLIKE(4)

如果您执行以下操作,GCC将向您发出一个很好的错误:

string_format( "Two things %d %d", only_one_thing );

(如果格式类型错误,它也会抱怨。

我不知道是什么导致了您的问题,但我看不出使用模板函数有什么好处。您可以使用好的老式varargs来实现这一点

我想说的是,编写varargs函数的黄金法则是编写一个采用
va_list
的函数。您的编辑非常清楚地说明了这一点——您通常会从另一个varargs函数调用varags函数

#include <stdarg.h>  // varargs support

static std::string string_vformat( const std::string& format, va_list args)
{
    va_list args_copy;
    va_copy(args,args_copy);  // Copy args before we use it.
                              // +1 is extra space for '\0'
    const size_t size = vsnprintf( nullptr, 0, format.c_str(), args_copy ) + 1; 
    va_end(args_copy);        // Release args_copy.
    std::unique_ptr<char[]> buf( new char[ size ] );
    vsnprintf( buf.get(), size, format.c_str(), args );
    // Caller must va_end(args);
           // We don't want the '\0' inside
    return std::string( buf.get(), buf.get() + size - 1 );
}

static std::string string_format( const std::string& format, ... )
{
    va_list args;
    va_start(format, args);
    const auto result = string_vformat(format, args);
    va_end(args);
    return result;
}

void user_log_fmt(LOG_LEVEL level,  std::string pretty_func, std::string func_name,
                                    std::string str_format, ... )
{
    if (m_LogLevel < level)
        return;

    va_list args;
    va_start(format, args);
    std::string formatted_data = utils::Utils::string_vformat(str_format, args);
    // Do something with the formatted string.. 
}
然后你可以声明:

 void user_log_fmt(LOG_LEVEL level, std::string pretty_func, std::string func_name,
                  std::string str_format, ... ) PRINTFLIKE(4)

如果您执行以下操作,GCC将向您发出一个很好的错误:

string_format( "Two things %d %d", only_one_thing );

(如果格式错误,也会抱怨。

@ SoavavHOH谢谢。),SNPrTNF与C有关,我把它标记为C。内容存储为C字符串。@萨米,很好,但是IMSO这个问题是基于C++语言来寻找答案的,C和C++是不一样的。它涉及C++与C的可兼容性,但我t与C语言无关-因此标记是不合适的。@Sammy:这些错误是来自模板的声明,还是来自用法?如果是后者,您能否显示调用(以及所有相关的声明)。Ubuntu错误看起来像是在调用
string\u格式(“Hello World”)
。Pi错误看起来像
std::string foo=“foo”string_格式(“Hello%s”,foo)“代码/ SNPrTNFF <代码>是C函数,但你传递的东西只不过是C++的。这肯定不能可靠地工作。如果我正确地阅读C++标准的代码> 18.103</代码>,那么传递不符合参数列表的任何东西是不确定的行为。换句话说,你最好做PURLE。y
C
C
兼容工作,如果您正在使用
varargs
函数,如
snprintf
printf
,等等。@SouravGhosh感谢您指出。但是snprintf确实与C有关,这是我将其标记为C的原因。内容存储为C-string。@Sammy这很好,但我怎么看这个问题