Clean code to printf size_t in C++ (or: Nearest equivalent of C99's %z in C++)

前端 未结 9 2572
醉梦人生
醉梦人生 2020-12-07 14:20

I have some C++ code that prints a size_t:

size_t a;
printf(\"%lu\", a);

I\'d like this to compile without warnings on both 32

相关标签:
9条回答
  • 2020-12-07 14:51

    The effective type underlying size_t is implementation dependent. C Standard defines it as the type returned by the sizeof operator; aside from being unsigned and a sort of integral type, the size_t can be pretty much anything which size can accommodate the biggest value expected to be returned by sizeof().

    Consequently the format string to be used for a size_t may vary depending on the server. It should always have the "u", but may be l or d or maybe something else...

    A trick could be to cast it to the biggest integral type on the machine, ensuring no loss in the conversion, and then using the format string associated with this known type.

    0 讨论(0)
  • 2020-12-07 14:52

    The printf format specifier %zu will work fine on C++ systems; there is no need to make it more complicated.

    0 讨论(0)
  • 2020-12-07 14:55

    #include <cstdio>
    #include <string>
    #include <type_traits>
    
    namespace my{
        template<typename ty>
        auto get_string(ty&& arg){
            using rty=typename::std::decay_t<::std::add_const_t<ty>>;
            if constexpr(::std::is_same_v<char, rty>)
                return ::std::string{1,arg};
            else if constexpr(::std::is_same_v<bool, rty>)
                return ::std::string(arg?"true":"false");
            else if constexpr(::std::is_same_v<char const*, rty>)
                return ::std::string{arg};
            else if constexpr(::std::is_same_v<::std::string, rty>)
                return ::std::forward<ty&&>(arg);
            else
                return ::std::to_string(arg);
        };
    
        template<typename T1, typename ... Args>
        auto printf(T1&& a1, Args&&...arg){
            auto str{(get_string(a1)+ ... + get_string(arg))};
            return ::std::printf(str.c_str());
        };
    };
    

    Later in code:

    my::printf("test ", 1, '\t', 2.0);

    0 讨论(0)
  • 2020-12-07 14:56

    here's a possible solution, but it's not quite a pretty one..

    template< class T >
    struct GetPrintfID
    {
      static const char* id;
    };
    
    template< class T >
    const char* GetPrintfID< T >::id = "%u";
    
    
    template<>
    struct GetPrintfID< unsigned long long > //or whatever the 64bit unsigned is called..
    {
      static const char* id;
    };
    
    const char* GetPrintfID< unsigned long long >::id = "%lu";
    
    //should be repeated for any type size_t can ever have
    
    
    printf( GetPrintfID< size_t >::id, sizeof( x ) );
    
    0 讨论(0)
  • 2020-12-07 14:57

    Since you're using C++, why not use IOStreams? That should compile without warnings and do the right type-aware thing, as long as you're not using a brain-dead C++ implementation that doesn't define an operator << for size_t.

    When the actual output has to be done with printf(), you can still combine it with IOStreams to get type-safe behavior:

    size_t foo = bar;
    ostringstream os;
    os << foo;
    printf("%s", os.str().c_str());
    

    It's not super-efficient, but your case above deals with file I/O, so that's your bottleneck, not this string formatting code.

    0 讨论(0)
  • 2020-12-07 15:03

    On windows and the Visual Studio implementation of printf

     %Iu
    

    works for me. see msdn

    0 讨论(0)
提交回复
热议问题