【问题标题】:How to detect when I am passing a `std::string`, instead of a `c_str()` to my variadic function?如何检测我何时将 `std::string` 而不是 `c_str()` 传递给我的可变参数函数?
【发布时间】:2017-07-10 11:30:35
【问题描述】:

如何检测我何时将std::string 而不是c_str() 传递给我的可变参数函数?

我最初的问题是,当我将std::string(而不是c_str(),即std::string s.c_str())传递给我的可变参数函数时,如果我在Sublime Text 上从shell script 运行,我的程序就会运行建造。如果我通过 std::string 并尝试从 Sublime Text 运行,这就是正在发生的事情:

rm -f main.exe
g++ --std=c++11 main.cpp -I . -o main
Starting the main program...

[Finished in 3.4s]

但如果我从带有./main 的shell 中运行,一切正常,除了字符串打印:

Starting the main program...

argumentsCount: 3
argumentsStringList[0]: ./main
argumentsStringList[1]: 1
argumentsStringList[2]: 2

SourceCode::SourceCode(1) text_code: ▒
Exiting main(2)

这是我的解析函数:

/**
 * Missing string printf. This is safe and convenient but not exactly efficient.
 *
 * @param fmt     a char array
 * @param ...     a variable length number of formating characters.
 *
 * @see http://stackoverflow.com/a/10150393/4934640
 * @see http://stackoverflow.com/questions/2342162/stdstring-formatting-like-sprintf/10150393#10150393
 */
inline std::string format(const char* fmt, ...)
{
    int   size   = 512;
    char* buffer = new char[size];

    va_list var_args;
    va_start(var_args, fmt);

    int nsize = vsnprintf(buffer, size, fmt, var_args);

    //fail delete buffer and try again
    if(size<=nsize)
    {
        delete[] buffer;

        buffer = 0;
        buffer = new char[nsize+1]; //+1 for /0
        nsize  = vsnprintf(buffer, size, fmt, var_args);
    }

    std::string ret(buffer);
    va_end(var_args);

    delete[] buffer;
    return ret;
}

这是我的暂定。这是一个最小的实际示例,您可以在自己的计算机上运行它,使用g++ --std=c++11 main.cpp -o main 编译:

#include <cstdlib>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <cstdarg>
#include <typeinfo>

inline std::string format(const char* fmt, ...)
{
    int   size   = 512;
    char* buffer = new char[size];

    std::string* temp;
    va_list var_args_copy;

    printf( "%s\n", fmt );
    va_start(var_args_copy, fmt);

    do
    {
        temp = va_arg( var_args_copy, std::string* );

        if( typeid( temp ) == typeid( std::string* ) )
        {
            std::string message( "ERROR!!!!!!!!!!!!!! Bad formatted string!\n" );
            return message;
        }

    } while( temp != NULL );

    va_list var_args;
    va_start(var_args, fmt);

    int nsize = vsnprintf(buffer, size, fmt, var_args);

    //fail delete buffer and try again
    if(size<=nsize)
    {
        delete[] buffer;

        buffer = 0;
        buffer = new char[nsize+1]; //+1 for /0
        nsize  = vsnprintf(buffer, size, fmt, var_args);
    }

    std::string ret(buffer);
    va_end(var_args);

    delete[] buffer;
    return ret;
}

int main( int argumentsCount, char* argumentsStringList[] )
{
    printf( "" );

    std::string strin( "String" );

    std::cout << format( "1. The string is %s", strin ) << std::endl;
    std::cout << format( "2. The string is %s", strin.c_str() ) << std::endl;

    printf( "Exiting main(2)" );
    return EXIT_SUCCESS;
}

运行我的试探,它输出我这个:

g++ -std=c++11 main2.cpp -I . -o main
1. The string is %s
ERROR!!!!!!!!!!!!!! Bad formatted string!

2. The string is %s
ERROR!!!!!!!!!!!!!! Bad formatted string!

Exiting main(2)[Finished in 3.7s]

这里2. The string is %s上的ERROR!!!!!!!!!!!!!! Bad formatted string!一定不能打印,因为它不是std::stringtypeid( temp ) == typeid( std::string* ) 让它过去有什么问题?

无论如何,另一种可能的解决方案可能只是接受std::string 而不是c_str(),即std::string s.c_str()

【问题讨论】:

  • 这就是关于 C 可变参数的事情。他们很不安全。如果您想要类型安全,请使用可变参数模板。
  • 你不能用笨拙的 C 风格的可变参数来做到这一点。没有什么关于随机的内存块说“我是std::string,我是c_str()”。如果您想正确执行此操作,请使用正确的 C++ 模板。

标签: c++ string c++11 stl std


【解决方案1】:

我找到了一个第三方库(include),它使用了可变参数模板,解决了这个问题。

  1. https://github.com/c42f/tinyformat

这是现在的代码:

#include <cstdlib>
#include "libraries/tinyformat/tinyformat.h"

int main( int argumentsCount, char* argumentsStringList[] )
{
    printf( "" );

    std::string strin( "String" );

    std::cout << tfm::format( "1. The string is %s", strin ) << std::endl;
    std::cout << tfm::format( "2. The string is %s", strin.c_str() ) << std::endl;

    printf( "Exiting main(2)\n" );
    return EXIT_SUCCESS;
}

正确输出:

rm -f main.exe
g++ -std=c++11 main2.cpp -I . -o main
1. The string is String
2. The string is String
Exiting main(2)
[Finished in 4.3s]

【讨论】:

    猜你喜欢
    • 2011-04-18
    • 1970-01-01
    • 2020-07-28
    • 2016-04-16
    • 1970-01-01
    • 2014-02-19
    • 2011-01-10
    • 1970-01-01
    • 2021-03-26
    相关资源
    最近更新 更多