How to printf to std::string by using of a function?

Manda Rajo 141 Reputation points
2022-04-15T05:52:03.223+00:00

Hi, I want to printf to std::string by using of a function, but I cannot do it.

EDIT from answer: Use vsnprintf instead of snprintf.

#include <string> // std::string
using std::string;
#include <stdarg.h> // va_list, va_start, va_arg, va_end

#define EMC_VERIFY(x) // TODO: Replace this.
#define SAFE_FREE(p) { if (p) { free (p); (p)=nullptr; } } ((void)0) // There must be ";".

string string_sprintf(const char *format, ...) {
    va_list args;
    va_start(args, format);
        // Referenced from https://stackoverflow.com/questions/436367/best-way-to-safely-printf-to-a-string
        size_t sz = vsnprintf(nullptr, 0, format, args);
        size_t bufsize = sz + 1;
        char *buf = (char *)malloc(bufsize);
        EMC_VERIFY(buf != nullptr);
        vsnprintf(buf, bufsize, format, args);
        //buf[bufsize - 1] = '\0'; // This line is not necessary, check the official documentation of vsnprintf for proof.
    va_end(args);
    string str = buf;
    SAFE_FREE(buf);
    return str;
}
int main()
{
    string s = string_sprintf("Hello World %d %d", 11, 22);
    return 0;
}

Wrong Result when using of snprintf:
s = "Hello World 7862840 7863104"
Why it doesn't work? And how to fix it?

Fixed Result when using of vsnprintf:
s = "Hello World 11 22"

Developer technologies C++
{count} votes

Accepted answer
  1. YujianYao-MSFT 4,296 Reputation points Microsoft External Staff
    2022-04-15T07:04:49.107+00:00

    Hi @Manda Rajo ,

    I suggest you try this sample:

    #include <cstdio>  
    #include <string>  
    #include <cassert>  
    #include<iostream>  
    template< typename... Args >  
    std::string string_sprintf(const char* format, Args... args) {  
    	int length = std::snprintf(nullptr, 0, format, args...);  
    	assert(length >= 0);  
      
    	char* buf = new char[length + 1];  
    	std::snprintf(buf, length + 1, format, args...);  
      
    	std::string str(buf);  
    	delete[] buf;  
    	return str;  
    }  
    template<typename ... Args>  
    std::string string_format(const std::string& format, Args ... args)  
    {  
    	int size_s = std::snprintf(nullptr, 0, format.c_str(), args ...) + 1; // Extra space for '\0'  
    	if (size_s <= 0) { throw std::runtime_error("Error during formatting."); }  
    	auto size = static_cast<size_t>(size_s);  
    	std::unique_ptr<char[]> buf(new char[size]);  
    	std::snprintf(buf.get(), size, format.c_str(), args ...);  
    	return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside  
    }  
    int main()  
    {  
    	std::cout << string_sprintf("sdad\n");  
    	std::cout << string_sprintf("%g, %g\n", 1.23, 0.001);  
    	  
    	return 0;  
    }  
    

    Best regards,

    Elya


    If the answer is the right solution, please click "Accept Answer" and upvote it.If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

2 additional answers

Sort by: Most helpful
  1. Manda Rajo 141 Reputation points
    2022-04-15T09:34:08.273+00:00

    I cannot place that function in a common project, because if I make it inline in a header file in the common project then another error because EMC_VERIFY is cross-platform such as on Windows, it requires MessageBox and MB_OK, and the most difficult is it requires "Windows.h" which is the most difficult to place, because I must always place it as last include.
    So I don't make it inline by declaring in a header file and put the definition in a .cpp file as below, and I got errors, I'm sure it's because I'm using a template.

    Location: Project "emc-common" > "emc-common_internal.h"

       template<typename... Args>  
       string string_sprintf(const char *format, Args... args);  
    

    Location: Project "emc-common" > "emc-common_internal.cpp"

       template<typename... Args>  
       string string_sprintf(const char *format, Args... args) {  
           // Originated from https://learn.microsoft.com/en-us/answers/questions/813614/how-to-printf-to-stdstring-by-using-of-a-function.html  
           int length = std::snprintf(nullptr, 0, format, args...);  
           EMC_VERIFY(length >= 0);  
    
           size_t sz = length + 1; // Extra space for '\0'  
           char *buf = (char *)malloc(sz);  
           std::snprintf(buf, sz, format, args...);  
    
           string str = buf;  
           SAFE_FREE(buf);  
           return str;  
       }  
    

    Location: Project "emc-language" > "emc-language.cpp"

       string g_output = "";  
       #define print(...) \  
           do { \  
               g_output += string_sprintf(__VA_ARGS__); \  
           } while(0)  
    

    Error:

    `

    emc-language_debug.lib(emc-language.obj) : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl string_sprintf<char const *>(char const *,char const *)" (??$string_sprintf@PEBD@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PEBD0@Z) referenced in function "void __cdecl printBuiltin(struct emcl::astBuiltin *)" (?printBuiltin@@YAXPEAUastBuiltin@emcl@@@Z)

    `

    `

    emc-language_debug.lib(emc-language.obj) : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl string_sprintf<char *>(char const *,char *)" (??$string_sprintf@PEAD@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PEBDPEAD@Z) referenced in function "void __cdecl printType(struct emcl::astType *)" (?printType@@YAXPEAUastType@emcl@@@Z)

    `

    `

    emc-language_debug.lib(emc-language.obj) : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl string_sprintf<int>(char const *,int)" (??$string_sprintf@H@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PEBDH@Z) referenced in function "void __cdecl printIntConstant(struct emcl::astIntConstant *)" (?printIntConstant@@YAXPEAUastIntConstant@emcl@@@Z)

    `

    `

    emc-language_debug.lib(emc-language.obj) : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl string_sprintf<unsigned int>(char const *,unsigned int)" (??$string_sprintf@I@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PEBDI@Z) referenced in function "void __cdecl printUIntConstant(struct emcl::astUIntConstant *)" (?printUIntConstant@@YAXPEAUastUIntConstant@emcl@@@Z)

    `

    `

    emc-language_debug.lib(emc-language.obj) : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl string_sprintf<float>(char const *,float)" (??$string_sprintf@M@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PEBDM@Z) referenced in function "void __cdecl printFloatConstant(struct emcl::astFloatConstant *)" (?printFloatConstant@@YAXPEAUastFloatConstant@emcl@@@Z)

    `

    `

    emc-language_debug.lib(emc-language.obj) : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl string_sprintf<double>(char const *,double)" (??$string_sprintf@N@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PEBDN@Z) referenced in function "void __cdecl printDoubleConstant(struct emcl::astDoubleConstant *)" (?printDoubleConstant@@YAXPEAUastDoubleConstant@emcl@@@Z)

    `

    `

    emc-language_debug.lib(emc-language.obj) : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl string_sprintf<>(char const *)" (??$string_sprintf@$$V@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PEBD@Z) referenced in function "void __cdecl printStatement(struct emcl::astStatement *)" (?printStatement@@YAXPEAUastStatement@emcl@@@Z)

    `

    0 comments No comments

  2. Manda Rajo 141 Reputation points
    2022-04-15T10:19:33.813+00:00

    The solution for that error is to use string string_sprintf(const char *format, ...); from the first post because it doesn't use tamplate, and I did it and there is no error, I made a big EDIT on the first post by inspiring from all the answers, so "Thank you very much".

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.