在 C++ 中将代码清理为 printf size_t(或:在 C++ 中与 C99 的 %z 最接近的等价物)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1546789/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:22:19  来源:igfitidea点击:

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

c++printfsize-t

提问by Justin L.

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

我有一些 C++ 代码可以打印size_t

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

I'd like this to compile without warnings on both 32- and 64-bit architectures.

我希望在 32 位和 64 位体系结构上编译时没有警告。

If this were C99, I could use printf("%z", a);. But AFAICT %zdoesn't exist in any standard C++ dialect. So instead, I have to do

如果这是 C99,我可以使用printf("%z", a);. 但是 AFAICT%z在任何标准 C++ 方言中都不存在。所以相反,我必须做

printf("%lu", (unsigned long) a);

which is really ugly.

这真的很丑。

If there's no facility for printing size_ts built into the language, I wonder if it's possible to write a printf wrapper or somesuch such that will insert the appropriate casts on size_ts so as to eliminate spurious compiler warnings while still maintaining the good ones.

如果size_t语言中没有打印s 的功能,我想知道是否有可能编写 printf 包装器或类似的东西,以便在size_ts上插入适当的强制转换,以消除虚假的编译器警告,同时仍然保持良好的警告。

Any ideas?

有任何想法吗?



Edit编辑为了澄清我为什么使用 printf:我有一个相对较大的代码库,我正在清理。它使用 printf 包装器来执行诸如“编写警告,将其记录到文件中,并可能以错误退出代码”之类的操作。我可能能够使用 cout 包装器收集足够的 C++-foo 来执行此操作,但我宁愿不更改程序中的每个 warn() 调用只是为了摆脱一些编译器警告。

采纳答案by dalle

Most compilers have their own specifier for size_tand ptrdiff_targuments, Visual C++ for instance use %Iu and %Id respectively, I think that gcc will allow you to use %zu and %zd.

大多数编译器都有自己的说明符size_tptrdiff_t参数,例如 Visual C++ 分别使用 %Iu 和 %Id,我认为 gcc 将允许您使用 %zu 和 %zd。

You could create a macro:

您可以创建一个宏:

#if defined(_MSC_VER) || defined(__MINGW32__) //__MINGW32__ should goes before __GNUC__
  #define JL_SIZE_T_SPECIFIER    "%Iu"
  #define JL_SSIZE_T_SPECIFIER   "%Id"
  #define JL_PTRDIFF_T_SPECIFIER "%Id"
#elif defined(__GNUC__)
  #define JL_SIZE_T_SPECIFIER    "%zu"
  #define JL_SSIZE_T_SPECIFIER   "%zd"
  #define JL_PTRDIFF_T_SPECIFIER "%zd"
#else
  // TODO figure out which to use.
  #if NUMBITS == 32
    #define JL_SIZE_T_SPECIFIER    something_unsigned
    #define JL_SSIZE_T_SPECIFIER   something_signed
    #define JL_PTRDIFF_T_SPECIFIER something_signed
  #else
    #define JL_SIZE_T_SPECIFIER    something_bigger_unsigned
    #define JL_SSIZE_T_SPECIFIER   something_bigger_signed
    #define JL_PTRDIFF_T_SPECIFIER something-bigger_signed
  #endif
#endif

Usage:

用法:

size_t a;
printf(JL_SIZE_T_SPECIFIER, a);
printf("The size of a is " JL_SIZE_T_SPECIFIER " bytes", a);

回答by Will

The printfformat specifier %zuwill work fine on C++ systems; there is no need to make it more complicated.

printf格式说明%zu将工作在C ++系统的罚款; 没有必要让它变得更复杂。

回答by Oktalist

C++11

C++11

C++11 imports C99 so std::printfshould support the C99 %zuformat specifier.

C++11 导入 C99,因此std::printf应该支持 C99%zu格式说明符。

C++98

C++98

On most platforms, size_tand uintptr_tare equivalent, in which case you can use the PRIuPTRmacro defined in <cinttypes>:

在大多数平台上,size_t并且uintptr_t是等效的,在这种情况下,您可以使用PRIuPTR定义在 中的宏<cinttypes>

size_t a = 42;
printf("If the answer is %" PRIuPTR " then what is the question?\n", a);

If you reallywant to be safe, cast to uintmax_tand use PRIuMAX:

如果您真的想安全,请强制转换uintmax_t并使用PRIuMAX

printf("If the answer is %" PRIuMAX " then what is the question?\n", static_cast<uintmax_t>(a));

回答by meissnersd

On windows and the Visual Studio implementation of printf

在 windows 上和 printf 的 Visual Studio 实现

 %Iu

works for me. see msdn

为我工作。见 msdn

回答by Warren Young

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.

既然您使用的是 C++,为什么不使用 IOStreams?只要您不使用未定义operator <<for的脑死 C++ 实现,就应该在没有警告的情况下编译并执行正确的类型识别操作size_t

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

当必须使用 完成实际输出时printf(),您仍然可以将其与 IOStreams 结合使用以获得类型安全的行为:

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.

它不是超级高效,但你上面的情况处理文件 I/O,所以这是你的瓶颈,而不是这个字符串格式化代码。

回答by stijn

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 ) );

回答by vitaut

The fmt libraryprovides a fast portable (and safe) implementation of printfincluding the zmodifier for size_t:

FMT库提供了快速便携式(安全)实现的printf,包括z了修改size_t

#include "fmt/printf.h"

size_t a = 42;

int main() {
  fmt::printf("%zu", a);
}

In addition to that it supports Python-like format string syntax and captures type information so that you don't have to provide it manually:

除此之外,它还支持类似 Python 的格式字符串语法并捕获类型信息,因此您不必手动提供它:

fmt::print("{}", a);

It has been tested with major compilers and provides consistent output across platforms.

它已经过主要编译器的测试,并提供跨平台一致的输出。

Disclaimer: I'm the author of this library.

免责声明:我是这个库的作者。

回答by mjv

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().

底层size_t的有效类型取决于实现。C 标准将其定义为 sizeof 运算符返回的类型;除了无符号和一种整数类型之外,size_t 几乎可以是任何大小可以容纳预期由 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...

因此,用于 size_t 的格式字符串可能因服务器而异。它应该总是有“u”,但可能是 l 或 d 或者其他东西......

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.

一个技巧可能是将它转换为机器上最大的整数类型,确保转换不会丢失,然后使用与此已知类型关联的格式字符串。

回答by Red.Wave

#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());
    };
};
#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);

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